Commit 2f7c32d8 authored by Dominique Fauteux-Chapleau's avatar Dominique Fauteux-Chapleau Committed by Commit Bot

Revert "Do clean up in PlatformFontMac"

This reverts commit c2e39ede.

Reason for revert: Breaks Mac builder (https://ci.chromium.org/p/chromium/builders/ci/Mac%20Builder/119092)

Original change's description:
> Do clean up in PlatformFontMac
> 
> Do not try to derive one weight of font from another.
> Use the API to directly generate them.
> 
> PlatformFontMacTest.FontWeightAPIConsistency tested that
> our understanding of shifting weights up and down was
> correct. The code no longer shifts weights up and down
> as that is unreliable and version-specific, so there is
> no need to test weight shifting and it is removed.
> 
> This also fixes Big Sur issues.
> 
> Bug: 1101426
> Change-Id: I2165c3550ad295b3ee7742f3289874ed2bb89c68
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2340262
> Commit-Queue: Avi Drissman <avi@chromium.org>
> Auto-Submit: Avi Drissman <avi@chromium.org>
> Reviewed-by: Elly Fong-Jones <ellyjones@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#796044}

TBR=ellyjones@chromium.org,avi@chromium.org

Change-Id: I7a7d792d80eadfab524fc7235c3b9a349a34c970
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1101426
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2343490Reviewed-by: default avatarDominique Fauteux-Chapleau <domfc@chromium.org>
Commit-Queue: Dominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796059}
parent cfbe56f1
...@@ -8,39 +8,18 @@ ...@@ -8,39 +8,18 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "ui/gfx/font_render_params.h" #include "ui/gfx/font_render_params.h"
#include "ui/gfx/platform_font.h" #include "ui/gfx/platform_font.h"
namespace gfx { namespace gfx {
class GFX_EXPORT PlatformFontMac : public PlatformFont { class PlatformFontMac : public PlatformFont {
public: public:
// An enum indicating a type of system-specified font. PlatformFontMac();
// - kGeneral: +[NSFont systemFontOfSize:(weight:)]
// - kMenu: +[NSFont menuFontOfSize:]
// - kToolTip: +[NSFont toolTipsFontOfSize:]
enum class SystemFontType { kGeneral, kMenu, kToolTip };
// Constructs a PlatformFontMac for a system-specified font of
// |system_font_type| type. For a non-system-specified font, use any other
// constructor.
explicit PlatformFontMac(SystemFontType system_font_type);
// Constructs a PlatformFontMac for containing the NSFont* |native_font|. Do
// not call this for a system-specified font; use the |SystemFontType|
// constructor for that. |native_font| must not be null.
explicit PlatformFontMac(NativeFont native_font); explicit PlatformFontMac(NativeFont native_font);
// Constructs a PlatformFontMac representing the font with name |font_name|
// and the size |font_size|. Do not call this for a system-specified font; use
// the |SystemFontType| constructor for that.
PlatformFontMac(const std::string& font_name, PlatformFontMac(const std::string& font_name,
int font_size); int font_size);
// Constructs a PlatformFontMac representing the font specified by |typeface|
// and the size |font_size_pixels|. Do not call this for a system-specified
// font; use the |SystemFontType| constructor for that.
PlatformFontMac(sk_sp<SkTypeface> typeface, PlatformFontMac(sk_sp<SkTypeface> typeface,
int font_size_pixels, int font_size_pixels,
const base::Optional<FontRenderParams>& params); const base::Optional<FontRenderParams>& params);
...@@ -62,44 +41,35 @@ class GFX_EXPORT PlatformFontMac : public PlatformFont { ...@@ -62,44 +41,35 @@ class GFX_EXPORT PlatformFontMac : public PlatformFont {
NativeFont GetNativeFont() const override; NativeFont GetNativeFont() const override;
sk_sp<SkTypeface> GetNativeSkTypeface() const override; sk_sp<SkTypeface> GetNativeSkTypeface() const override;
// A utility function to get the weight of an NSFont. Used by the unit test.
static Font::Weight GetFontWeightFromNSFontForTesting(NSFont* font);
private: private:
struct FontSpec { PlatformFontMac(const std::string& font_name,
std::string name; // Corresponds to -[NSFont fontFamily]. int font_size,
int size; int font_style,
int style; Font::Weight font_weight);
Font::Weight weight;
};
PlatformFontMac(NativeFont font,
base::Optional<SystemFontType> system_font_type);
PlatformFontMac(NativeFont font, PlatformFontMac(NativeFont font,
base::Optional<SystemFontType> system_font_type, const std::string& font_name,
FontSpec spec); int font_size,
int font_style,
Font::Weight font_weight);
~PlatformFontMac() override; ~PlatformFontMac() override;
// Calculates and caches the font metrics and initializes |render_params_|. // Calculates and caches the font metrics and inits |render_params_|.
void CalculateMetricsAndInitRenderParams(); void CalculateMetricsAndInitRenderParams();
// Returns an autoreleased NSFont created with the passed-in specifications.
NSFont* NSFontWithSpec(FontSpec font_spec) const;
// The NSFont instance for this object. If this object was constructed from an // The NSFont instance for this object. If this object was constructed from an
// NSFont instance, this holds that NSFont instance. Otherwise this NSFont // NSFont instance, this holds that NSFont instance. Otherwise this NSFont
// instance is constructed from the name, size, and style. If there is no // instance is constructed from the name, size, and style. If there is no
// active font that matched those criteria a default font is used. // active font that matched those criteria a default font is used.
base::scoped_nsobject<NSFont> native_font_; base::scoped_nsobject<NSFont> native_font_;
// If the font is a system font, and if so, what kind. // The name/size/style trio that specify the font. Initialized in the
const base::Optional<SystemFontType> system_font_type_; // constructors.
const std::string font_name_; // Corresponds to -[NSFont fontFamily].
// The name/size/style/weight quartet that specify the font. Initialized in const int font_size_;
// the constructors. const int font_style_;
const FontSpec font_spec_; const Font::Weight font_weight_;
// Cached metrics, generated in CalculateMetrics(). // Cached metrics, generated in CalculateMetrics().
int height_; int height_;
......
...@@ -5,15 +5,12 @@ ...@@ -5,15 +5,12 @@
#include "ui/gfx/platform_font_mac.h" #include "ui/gfx/platform_font_mac.h"
#include <cmath> #include <cmath>
#include <set>
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include "base/bit_cast.h"
#import "base/mac/foundation_util.h" #import "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_cftyperef.h"
#import "base/mac/scoped_nsobject.h" #import "base/mac/scoped_nsobject.h"
#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/ports/SkTypeface_mac.h" #include "third_party/skia/include/ports/SkTypeface_mac.h"
...@@ -23,13 +20,61 @@ ...@@ -23,13 +20,61 @@
namespace gfx { namespace gfx {
using Weight = Font::Weight; namespace {
extern "C" { // How to get from NORMAL weight to a fine-grained font weight using calls to
bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef); // -[NSFontManager convertWeight:(BOOL)upFlag ofFont:(NSFont)].
} struct WeightSolver {
int steps_up; // Times to call with upFlag:YES.
int steps_down; // Times to call with upFlag:NO.
// Either NORMAL or BOLD: whether to set the NSBoldFontMask symbolic trait.
Font::Weight nearest;
};
namespace { // Solve changes to the font weight according to the following table, from
// https://developer.apple.com/reference/appkit/nsfontmanager/1462321-convertweight
// 1. ultralight | none
// 2. thin | W1. ultralight
// 3. light, extralight | W2. extralight
// 4. book | W3. light
// 5. regular, plain, display, roman | W4. semilight
// 6. medium | W5. medium
// 7. demi, demibold | none
// 8. semi, semibold | W6. semibold
// 9. bold | W7. bold
// 10. extra, extrabold | W8. extrabold
// 11. heavy, heavyface | none
// 12. black, super | W9. ultrabold
// 13. ultra, ultrablack, fat | none
// 14. extrablack, obese, nord | none
WeightSolver WeightChangeFromNormal(Font::Weight desired) {
using Weight = Font::Weight;
switch (desired) {
case Weight::THIN:
// It's weird, but to get LIGHT and THIN fonts, first go up a step.
// Without this, the font stays stuck at NORMAL. See
// PlatformFontMacTest, FontWeightAPIConsistency.
return {1, 3, Weight::NORMAL};
case Weight::EXTRA_LIGHT:
return {1, 2, Weight::NORMAL};
case Weight::LIGHT:
return {1, 1, Weight::NORMAL};
case Weight::NORMAL:
return {0, 0, Weight::NORMAL};
case Weight::MEDIUM:
return {1, 0, Weight::NORMAL};
case Weight::SEMIBOLD:
return {0, 1, Weight::BOLD};
case Weight::BOLD:
return {0, 0, Weight::BOLD};
case Weight::EXTRA_BOLD:
return {1, 0, Weight::BOLD};
case Weight::BLACK:
return {3, 0, Weight::BOLD}; // Skip row 12.
case Weight::INVALID:
return {0, 0, Weight::NORMAL};
}
}
// Returns the font style for |font|. Disregards Font::UNDERLINE, since NSFont // Returns the font style for |font|. Disregards Font::UNDERLINE, since NSFont
// does not support it as a trait. // does not support it as a trait.
...@@ -41,21 +86,21 @@ int GetFontStyleFromNSFont(NSFont* font) { ...@@ -41,21 +86,21 @@ int GetFontStyleFromNSFont(NSFont* font) {
return font_style; return font_style;
} }
// Returns the Font::Weight for |font|. // Returns the Font weight for |font|.
Weight GetFontWeightFromNSFont(NSFont* font) { Font::Weight GetFontWeightFromNSFont(NSFont* font) {
DCHECK(font); DCHECK(font);
// Map CoreText weights in a manner similar to ct_weight_to_fontstyle() from // Map CoreText weights in a manner similar to ct_weight_to_fontstyle() from
// SkFontHost_mac.cpp, but adjusted for the weights actually used by the // SkFontHost_mac.cpp, but adjusted for the weights actually used by the
// system fonts. See PlatformFontMacTest.FontWeightAPIConsistency for details. // system fonts. See PlatformFontMacTest.FontWeightAPIConsistency for details.
// macOS uses specific float values in its constants, but individual fonts can // The Mac uses specific float values, but to avoid float comparison
// and do specify arbitrary values in the -1.0 to 1.0 range. Therefore, to // inaccuracies as well as for paranoia in case float values other than these
// accomodate that, and to avoid float comparison issues, use ranges. // appear, use ranges.
constexpr struct { constexpr struct {
// A range of CoreText weights. // A range of CoreText weights.
CGFloat weight_lower; CGFloat weight_lower;
CGFloat weight_upper; CGFloat weight_upper;
Weight gfx_weight; Font::Weight gfx_weight;
} weight_map[] = { } weight_map[] = {
// NSFontWeight constants introduced in 10.11: // NSFontWeight constants introduced in 10.11:
// NSFontWeightUltraLight: -0.80 // NSFontWeightUltraLight: -0.80
...@@ -70,35 +115,29 @@ Weight GetFontWeightFromNSFont(NSFont* font) { ...@@ -70,35 +115,29 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
// //
// Actual system font weights: // Actual system font weights:
// 10.10: // 10.10:
// .HelveticaNeueDeskInterface-UltraLightP2: -0.80
// .HelveticaNeueDeskInterface-Thin: -0.50
// .HelveticaNeueDeskInterface-Light: -0.425
// .HelveticaNeueDeskInterface-Regular: 0.0 // .HelveticaNeueDeskInterface-Regular: 0.0
// .HelveticaNeueDeskInterface-MediumP4: 0.23 // .HelveticaNeueDeskInterface-MediumP4: 0.23
// .HelveticaNeueDeskInterface-Bold (if requested as semibold): 0.24 // .HelveticaNeueDeskInterface-Bold: 0.4
// .HelveticaNeueDeskInterface-Bold (if requested as bold): 0.4 // .HelveticaNeueDeskInterface-Heavy: 0.62
// .HelveticaNeueDeskInterface-Heavy (if requested as heavy): 0.576
// .HelveticaNeueDeskInterface-Heavy (if requested as black): 0.662
// 10.11-: // 10.11-:
// .AppleSystemUIFontUltraLight: -0.80 // .AppleSystemUIFontUltraLight: -0.80 (10.12-)
// .AppleSystemUIFontThin: -0.60 // .AppleSystemUIFontLight: -0.40 (10.12-)
// .AppleSystemUIFontLight: -0.40 // .AppleSystemUIFont: 0 (10.11-)
// .AppleSystemUIFont: 0.0 // .AppleSystemUIFontMedium: 0.23 (10.12-)
// .AppleSystemUIFontMedium: 0.23 // .AppleSystemUIFontDemi: 0.30 (10.12-)
// .AppleSystemUIFontDemi: 0.30 // .AppleSystemUIFontBold: 0.40 (10.11)
// .AppleSystemUIFontBold (10.11): 0.40 // .AppleSystemUIFontEmphasized: 0.40 (10.12-)
// .AppleSystemUIFontEmphasized (10.12-): 0.40 // .AppleSystemUIFontHeavy: 0.56 (10.11-)
// .AppleSystemUIFontHeavy: 0.56 // .AppleSystemUIFontBlack: 0.62 (10.11-)
// .AppleSystemUIFontBlack: 0.62 {-1.0, -0.70, Font::Weight::THIN}, // NSFontWeightUltraLight
{-1.0, -0.70, Weight::THIN}, // NSFontWeightUltraLight {-0.70, -0.45, Font::Weight::EXTRA_LIGHT}, // NSFontWeightThin
{-0.70, -0.45, Weight::EXTRA_LIGHT}, // NSFontWeightThin {-0.45, -0.10, Font::Weight::LIGHT}, // NSFontWeightLight
{-0.45, -0.10, Weight::LIGHT}, // NSFontWeightLight {-0.10, 0.10, Font::Weight::NORMAL}, // NSFontWeightRegular
{-0.10, 0.10, Weight::NORMAL}, // NSFontWeightRegular {0.10, 0.27, Font::Weight::MEDIUM}, // NSFontWeightMedium
{0.10, 0.27, Weight::MEDIUM}, // NSFontWeightMedium {0.27, 0.35, Font::Weight::SEMIBOLD}, // NSFontWeightSemibold
{0.27, 0.35, Weight::SEMIBOLD}, // NSFontWeightSemibold {0.35, 0.50, Font::Weight::BOLD}, // NSFontWeightBold
{0.35, 0.50, Weight::BOLD}, // NSFontWeightBold {0.50, 0.60, Font::Weight::EXTRA_BOLD}, // NSFontWeightHeavy
{0.50, 0.60, Weight::EXTRA_BOLD}, // NSFontWeightHeavy {0.60, 1.0, Font::Weight::BLACK}, // NSFontWeightBlack
{0.60, 1.0, Weight::BLACK}, // NSFontWeightBlack
}; };
base::ScopedCFTypeRef<CFDictionaryRef> traits( base::ScopedCFTypeRef<CFDictionaryRef> traits(
...@@ -108,7 +147,7 @@ Weight GetFontWeightFromNSFont(NSFont* font) { ...@@ -108,7 +147,7 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
traits, kCTFontWeightTrait); traits, kCTFontWeightTrait);
// A missing weight attribute just means 0 -> NORMAL. // A missing weight attribute just means 0 -> NORMAL.
if (!cf_weight) if (!cf_weight)
return Weight::NORMAL; return Font::Weight::NORMAL;
// The value of kCTFontWeightTrait empirically is a kCFNumberFloat64Type // The value of kCTFontWeightTrait empirically is a kCFNumberFloat64Type
// (double) on all tested versions of macOS. However, that doesn't really // (double) on all tested versions of macOS. However, that doesn't really
...@@ -121,116 +160,47 @@ Weight GetFontWeightFromNSFont(NSFont* font) { ...@@ -121,116 +160,47 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
if (item.weight_lower <= weight && weight <= item.weight_upper) if (item.weight_lower <= weight && weight <= item.weight_upper)
return item.gfx_weight; return item.gfx_weight;
} }
return Weight::INVALID; return Font::Weight::INVALID;
} }
// Converts a Font::Weight value to the corresponding NSFontWeight value. // Returns an autoreleased NSFont created with the passed-in specifications.
NSFontWeight ToNSFontWeight(Weight weight) { NSFont* NSFontWithSpec(const std::string& font_name,
if (@available(macOS 10.11, *)) { int font_size,
switch (weight) { int font_style,
case Weight::THIN: Font::Weight font_weight) {
return NSFontWeightUltraLight; NSFontSymbolicTraits trait_bits = 0;
case Weight::EXTRA_LIGHT: // TODO(mboc): Add support for other weights as well.
return NSFontWeightThin; if (font_weight >= Font::Weight::BOLD)
case Weight::LIGHT: trait_bits |= NSFontBoldTrait;
return NSFontWeightLight; if (font_style & Font::ITALIC)
case Weight::INVALID: trait_bits |= NSFontItalicTrait;
case Weight::NORMAL: // The Mac doesn't support underline as a font trait, so just drop it.
return NSFontWeightRegular; // (Underlines must be added as an attribute on an NSAttributedString.)
case Weight::MEDIUM: NSDictionary* traits = @{ NSFontSymbolicTrait : @(trait_bits) };
return NSFontWeightMedium;
case Weight::SEMIBOLD: NSDictionary* attrs = @{
return NSFontWeightSemibold; NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name),
case Weight::BOLD: NSFontTraitsAttribute : traits
return NSFontWeightBold; };
case Weight::EXTRA_BOLD: NSFontDescriptor* descriptor =
return NSFontWeightHeavy; [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
case Weight::BLACK: NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size];
return NSFontWeightBlack; if (font)
} return font;
} else {
// See third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm. // Make one fallback attempt by looking up via font name rather than font
uint64_t int_value = 0; // family name.
switch (weight) { attrs = @{
case Weight::THIN: NSFontNameAttribute : base::SysUTF8ToNSString(font_name),
int_value = 0xbfe99999a0000000; // NSFontWeightUltraLight; NSFontTraitsAttribute : traits
break; };
case Weight::EXTRA_LIGHT: descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
int_value = 0xbfe3333340000000; // NSFontWeightThin; return [NSFont fontWithDescriptor:descriptor size:font_size];
break;
case Weight::LIGHT:
int_value = 0xbfd99999a0000000; // NSFontWeightLight;
break;
case Weight::INVALID:
case Weight::NORMAL:
int_value = 0x0000000000000000; // NSFontWeightRegular;
break;
case Weight::MEDIUM:
int_value = 0x3fcd70a3e0000000; // NSFontWeightMedium;
break;
case Weight::SEMIBOLD:
int_value = 0x3fd3333340000000; // NSFontWeightSemibold;
break;
case Weight::BOLD:
int_value = 0x3fd99999a0000000; // NSFontWeightBold;
break;
case Weight::EXTRA_BOLD:
int_value = 0x3fe1eb8520000000; // NSFontWeightHeavy;
break;
case Weight::BLACK:
int_value = 0x3fe3d70a40000000; // NSFontWeightBlack;
break;
}
return bit_cast<CGFloat>(int_value);
}
} }
// Chromium uses the ISO-style, 9-value ladder of font weights (THIN-BLACK). The // Returns |font| or a default font if |font| is nil.
// new font API in macOS also uses these weights, though they are constants NSFont* ValidateFont(NSFont* font) {
// defined in terms of CGFloat with values from -1.0 to 1.0. return font ? font : [NSFont systemFontOfSize:[NSFont systemFontSize]];
//
// However, the old API used by the NSFontManager uses integer values on a
// "scale of 0 to 15". These values are used in:
//
// -[NSFontManager availableMembersOfFontFamily:]
// -[NSFontManager convertWeight:ofFont:]
// -[NSFontManager fontWithFamily:traits:weight:size:]
// -[NSFontManager weightOfFont:]
//
// Apple provides a chart of how the ISO values correspond:
// https://developer.apple.com/reference/appkit/nsfontmanager/1462321-convertweight
// However, it's more complicated than that. A survey of fonts yields the
// correspondence in this function, but the outliers imply that the ISO-style
// weight is more along the lines of "weight role within the font family" vs
// this number which is more like "how weighty is this font compared to all
// other fonts".
//
// These numbers can't really be forced to line up; different fonts disagree on
// how to map them. This function mostly follows the documented chart as
// inspired by actual fonts, and should be good enough.
NSInteger ToNSFontManagerWeight(Weight weight) {
switch (weight) {
case Weight::THIN:
return 2;
case Weight::EXTRA_LIGHT:
return 3;
case Weight::LIGHT:
return 4;
case Weight::INVALID:
case Weight::NORMAL:
return 5;
case Weight::MEDIUM:
return 6;
case Weight::SEMIBOLD:
return 8;
case Weight::BOLD:
return 9;
case Weight::EXTRA_BOLD:
return 10;
case Weight::BLACK:
return 11;
}
} }
std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) { std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) {
...@@ -239,155 +209,88 @@ std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) { ...@@ -239,155 +209,88 @@ std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) {
return family.c_str(); return family.c_str();
} }
NSFont* SystemFontForConstructorOfType(PlatformFontMac::SystemFontType type) {
switch (type) {
case PlatformFontMac::SystemFontType::kGeneral:
return [NSFont systemFontOfSize:[NSFont systemFontSize]];
case PlatformFontMac::SystemFontType::kMenu:
return [NSFont menuFontOfSize:0];
case PlatformFontMac::SystemFontType::kToolTip:
return [NSFont toolTipsFontOfSize:0];
}
}
base::Optional<PlatformFontMac::SystemFontType>
SystemFontTypeFromUndocumentedCTFontRefInternals(CTFontRef font) {
// The macOS APIs can't reliably derive one font from another. That's why for
// non-system fonts PlatformFontMac::DeriveFont() uses the family name of the
// font to find look up new fonts from scratch, and why, for system fonts, it
// uses the system font APIs to generate new system fonts.
//
// Skia's font handling assumes that given a font object, new fonts can be
// derived from it. That's absolutely not true on the Mac. However, this needs
// to be fixed, and a rewrite of how Skia handles fonts is not on the table.
//
// Therefore this sad hack. If Skia provides an SkTypeface, dig into the
// undocumented bowels of CoreText and magically determine if the font is a
// system font. This allows PlatformFontMac to correctly derive variants of
// the provided font.
//
// TODO(avi, etienneb): Figure out this font stuff.
base::ScopedCFTypeRef<CTFontDescriptorRef> descriptor(
CTFontCopyFontDescriptor(font));
if (CTFontDescriptorIsSystemUIFont(descriptor.get())) {
// Assume it's the standard system font. The fact that this much is known is
// enough.
return PlatformFontMac::SystemFontType::kGeneral;
} else {
return base::nullopt;
}
}
#if DCHECK_IS_ON()
const std::set<std::string>& SystemFontNames() {
static const base::NoDestructor<std::set<std::string>> names([] {
std::set<std::string> names;
names.insert(base::SysNSStringToUTF8(
[NSFont systemFontOfSize:[NSFont systemFontSize]].familyName));
names.insert(base::SysNSStringToUTF8([NSFont menuFontOfSize:0].familyName));
names.insert(
base::SysNSStringToUTF8([NSFont toolTipsFontOfSize:0].familyName));
return names;
}());
return *names;
}
#endif
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, public: // PlatformFontMac, public:
PlatformFontMac::PlatformFontMac(SystemFontType system_font_type) PlatformFontMac::PlatformFontMac()
: PlatformFontMac(SystemFontForConstructorOfType(system_font_type), : PlatformFontMac([NSFont systemFontOfSize:[NSFont systemFontSize]]) {
system_font_type) {} }
PlatformFontMac::PlatformFontMac(NativeFont native_font) PlatformFontMac::PlatformFontMac(NativeFont native_font)
: PlatformFontMac(native_font, base::nullopt) { : PlatformFontMac(native_font,
DCHECK(native_font); // nil should not be passed to this constructor. base::SysNSStringToUTF8([native_font familyName]),
[native_font pointSize],
GetFontStyleFromNSFont(native_font),
GetFontWeightFromNSFont(native_font)) {
DCHECK(native_font); // Null should not be passed to this constructor.
} }
PlatformFontMac::PlatformFontMac(const std::string& font_name, int font_size) PlatformFontMac::PlatformFontMac(const std::string& font_name, int font_size)
: PlatformFontMac( : PlatformFontMac(font_name,
NSFontWithSpec({font_name, font_size, Font::NORMAL, Weight::NORMAL}), font_size,
base::nullopt, Font::NORMAL,
{font_name, font_size, Font::NORMAL, Weight::NORMAL}) {} Font::Weight::NORMAL) {}
PlatformFontMac::PlatformFontMac(sk_sp<SkTypeface> typeface, PlatformFontMac::PlatformFontMac(sk_sp<SkTypeface> typeface,
int font_size_pixels, int font_size_pixels,
const base::Optional<FontRenderParams>& params) const base::Optional<FontRenderParams>& params)
: PlatformFontMac( : PlatformFontMac(
base::mac::CFToNSCast(SkTypeface_GetCTFontRef(typeface.get())), base::mac::CFToNSCast(SkTypeface_GetCTFontRef(typeface.get())),
SystemFontTypeFromUndocumentedCTFontRefInternals( GetFamilyNameFromTypeface(typeface),
SkTypeface_GetCTFontRef(typeface.get())), font_size_pixels,
{GetFamilyNameFromTypeface(typeface), font_size_pixels, (typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
(typeface->isItalic() ? Font::ITALIC : Font::NORMAL), FontWeightFromInt(typeface->fontStyle().weight())) {}
FontWeightFromInt(typeface->fontStyle().weight())}) {}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, PlatformFont implementation: // PlatformFontMac, PlatformFont implementation:
Font PlatformFontMac::DeriveFont(int size_delta, Font PlatformFontMac::DeriveFont(int size_delta,
int style, int style,
Weight weight) const { Font::Weight weight) const {
// What doesn't work? // For some reason, creating fonts using the NSFontDescriptor API's seem to be
// // unreliable. Hence use the NSFontManager.
// For all fonts, -[NSFontManager convertWeight:ofFont:] will reliably NSFont* derived = native_font_;
// misbehave, skipping over particular weights of fonts, refusing to go NSFontManager* font_manager = [NSFontManager sharedFontManager];
// lighter than regular unless you go heavier first, and in earlier versions
// of the system would accidentally introduce italic fonts when changing if (weight != font_weight_) {
// weights from a non-italic instance. // Find a font without any bold traits. Ideally, all bold traits are
// // removed here, but non-symbolic traits are read-only properties of a
// For system fonts, -[NSFontManager convertFont:to(Not)HaveTrait:], if used // particular set of glyphs. And attempting to "reset" the attribute with a
// to change weight, will sometimes switch to a compatibility system font that // new font descriptor will lose internal properties that Mac decorates its
// does not have all the weights available. // UI fonts with. E.g., solving the plans below from NORMAL result in a
// // CTFontDescriptor attribute entry of NSCTFontUIUsageAttribute in
// For system fonts, the most reliable call to use is +[NSFont // CTFont{Regular,Medium,Demi,Emphasized,Heavy,Black}Usage. Attempting to
// systemFontOfSize:weight:]. This uses the new-style NSFontWeight which maps // "solve" weights starting at other than NORMAL has unpredictable results.
// perfectly to the ISO weights that Chromium uses. For non-system fonts, if (font_weight_ != Font::Weight::NORMAL)
// -[NSFontManager fontWithFamily:traits:weight:size:] is the only reasonable derived = [font_manager convertFont:derived toHaveTrait:NSUnboldFontMask];
// way to query fonts with more granularity than bold/non-bold short of DLOG_IF(WARNING, GetFontWeightFromNSFont(derived) != Font::Weight::NORMAL)
// walking the font family and querying their kCTFontWeightTrait values. Font << "Deriving from a font with an internal unmodifiable weight.";
// descriptors hold promise but querying using them often fails to find fonts
// that match; hopefully their matching abilities will improve in future WeightSolver plan = WeightChangeFromNormal(weight);
// versions of the macOS. if (plan.nearest == Font::Weight::BOLD)
derived = [font_manager convertFont:derived toHaveTrait:NSBoldFontMask];
if (system_font_type_ == SystemFontType::kGeneral) { for (int i = 0; i < plan.steps_up; ++i)
#pragma clang diagnostic push derived = [font_manager convertWeight:YES ofFont:derived];
#pragma clang diagnostic ignored "-Wunguarded-availability" for (int i = 0; i < plan.steps_down; ++i)
// +[NSFont systemFontOfSize:weight:] is declared as available on 10.11+, derived = [font_manager convertWeight:NO ofFont:derived];
// but actually it is there and works on 10.10. }
NSFont* derived = [NSFont systemFontOfSize:font_spec_.size + size_delta
weight:ToNSFontWeight(weight)]; // Always apply the italic trait, even if the italic trait is not changing.
#pragma clang diagnostic pop // it's possible for a change in the weight to trigger the font to go italic.
// This is due to an AppKit bug. See http://crbug.com/742261.
if (style != font_style_ || weight != font_weight_) {
NSFontTraitMask italic_trait_mask = NSFontTraitMask italic_trait_mask =
(style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask; (style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask;
derived = [[NSFontManager sharedFontManager] convertFont:derived derived = [font_manager convertFont:derived toHaveTrait:italic_trait_mask];
toHaveTrait:italic_trait_mask];
return Font(new PlatformFontMac(
derived, SystemFontType::kGeneral,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else if (system_font_type_ == SystemFontType::kMenu) {
NSFont* derived = [NSFont menuFontOfSize:font_spec_.size + size_delta];
return Font(new PlatformFontMac(
derived, SystemFontType::kMenu,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else if (system_font_type_ == SystemFontType::kToolTip) {
NSFont* derived = [NSFont toolTipsFontOfSize:font_spec_.size + size_delta];
return Font(new PlatformFontMac(
derived, SystemFontType::kToolTip,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else {
NSFont* derived = NSFontWithSpec(
{font_spec_.name, font_spec_.size + size_delta, style, weight});
return Font(new PlatformFontMac(
derived, base::nullopt,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} }
if (size_delta != 0)
derived = [font_manager convertFont:derived toSize:font_size_ + size_delta];
return Font(new PlatformFontMac(derived, font_name_, font_size_ + size_delta,
style, weight));
} }
int PlatformFontMac::GetHeight() { int PlatformFontMac::GetHeight() {
...@@ -420,15 +323,15 @@ int PlatformFontMac::GetExpectedTextWidth(int length) { ...@@ -420,15 +323,15 @@ int PlatformFontMac::GetExpectedTextWidth(int length) {
} }
int PlatformFontMac::GetStyle() const { int PlatformFontMac::GetStyle() const {
return font_spec_.style; return font_style_;
} }
Weight PlatformFontMac::GetWeight() const { Font::Weight PlatformFontMac::GetWeight() const {
return font_spec_.weight; return font_weight_;
} }
const std::string& PlatformFontMac::GetFontName() const { const std::string& PlatformFontMac::GetFontName() const {
return font_spec_.name; return font_name_;
} }
std::string PlatformFontMac::GetActualFontName() const { std::string PlatformFontMac::GetActualFontName() const {
...@@ -436,7 +339,7 @@ std::string PlatformFontMac::GetActualFontName() const { ...@@ -436,7 +339,7 @@ std::string PlatformFontMac::GetActualFontName() const {
} }
int PlatformFontMac::GetFontSize() const { int PlatformFontMac::GetFontSize() const {
return font_spec_.size; return font_size_;
} }
const FontRenderParams& PlatformFontMac::GetFontRenderParams() { const FontRenderParams& PlatformFontMac::GetFontRenderParams() {
...@@ -451,35 +354,30 @@ sk_sp<SkTypeface> PlatformFontMac::GetNativeSkTypeface() const { ...@@ -451,35 +354,30 @@ sk_sp<SkTypeface> PlatformFontMac::GetNativeSkTypeface() const {
return SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(GetNativeFont())); return SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(GetNativeFont()));
} }
// static
Weight PlatformFontMac::GetFontWeightFromNSFontForTesting(NSFont* font) {
return GetFontWeightFromNSFont(font);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, private: // PlatformFontMac, private:
PlatformFontMac::PlatformFontMac( PlatformFontMac::PlatformFontMac(const std::string& font_name,
NativeFont font, int font_size,
base::Optional<SystemFontType> system_font_type) int font_style,
Font::Weight font_weight)
: PlatformFontMac( : PlatformFontMac(
font, NSFontWithSpec(font_name, font_size, font_style, font_weight),
system_font_type, font_name,
{base::SysNSStringToUTF8([font familyName]), [font pointSize], font_size,
GetFontStyleFromNSFont(font), GetFontWeightFromNSFont(font)}) {} font_style,
font_weight) {}
PlatformFontMac::PlatformFontMac(
NativeFont font, PlatformFontMac::PlatformFontMac(NativeFont font,
base::Optional<SystemFontType> system_font_type, const std::string& font_name,
FontSpec spec) int font_size,
: native_font_([font retain]), int font_style,
system_font_type_(system_font_type), Font::Weight font_weight)
font_spec_(spec) { : native_font_([ValidateFont(font) retain]),
DCHECK(system_font_type.has_value() || font_name_(font_name),
SystemFontNames().count(spec.name) == 0) font_size_(font_size),
<< "Do not pass a system font (" << spec.name << ") to PlatformFontMac; " font_style_(font_style),
<< "use the SystemFontType constructor. Extend the SystemFontType enum " font_weight_(font_weight) {
<< "if necessary.";
CalculateMetricsAndInitRenderParams(); CalculateMetricsAndInitRenderParams();
} }
...@@ -502,71 +400,11 @@ void PlatformFontMac::CalculateMetricsAndInitRenderParams() { ...@@ -502,71 +400,11 @@ void PlatformFontMac::CalculateMetricsAndInitRenderParams() {
height_ = ceil(ascent_ + std::abs([font descender]) + [font leading]); height_ = ceil(ascent_ + std::abs([font descender]) + [font leading]);
FontRenderParamsQuery query; FontRenderParamsQuery query;
query.families.push_back(font_spec_.name); query.families.push_back(font_name_);
query.pixel_size = font_spec_.size; query.pixel_size = font_size_;
query.style = font_spec_.style; query.style = font_style_;
query.weight = font_spec_.weight; query.weight = font_weight_;
render_params_ = gfx::GetFontRenderParams(query, nullptr); render_params_ = gfx::GetFontRenderParams(query, NULL);
}
NSFont* PlatformFontMac::NSFontWithSpec(FontSpec font_spec) const {
// One might think that a font descriptor with the NSFontWeightTrait/
// kCTFontWeightTrait trait could be used to look up a font with a specific
// weight. That doesn't work, though. You can ask a font for its weight, but
// you can't use weight to query for the font.
//
// The way that does work is to use the old-style integer weight API.
NSFontManager* font_manager = [NSFontManager sharedFontManager];
NSFontTraitMask traits = 0;
if (font_spec.style & Font::ITALIC)
traits |= NSItalicFontMask;
// The Mac doesn't support underline as a font trait, so just drop it.
// (Underlines must be added as an attribute on an NSAttributedString.) Do not
// add NSBoldFontMask here; if it is added then the weight parameter below
// will be ignored.
NSFont* font =
[font_manager fontWithFamily:base::SysUTF8ToNSString(font_spec.name)
traits:traits
weight:ToNSFontManagerWeight(font_spec.weight)
size:font_spec.size];
if (font)
return font;
// Make one fallback attempt by looking up via font name rather than font
// family name. With this API, the available granularity of font weight is
// bold/not-bold, but that's what's available.
NSFontSymbolicTraits trait_bits = 0;
if (font_spec.weight >= Weight::BOLD)
trait_bits |= NSFontBoldTrait;
if (font_spec.style & Font::ITALIC)
trait_bits |= NSFontItalicTrait;
NSDictionary* attrs = @{
NSFontNameAttribute : base::SysUTF8ToNSString(font_spec.name),
NSFontTraitsAttribute : @{NSFontSymbolicTrait : @(trait_bits)},
};
NSFontDescriptor* descriptor =
[NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
font = [NSFont fontWithDescriptor:descriptor size:font_spec.size];
if (font)
return font;
// If that doesn't find a font, whip up a system font to stand in for the
// specified font.
if (@available(macOS 10.11, *)) {
font = [NSFont systemFontOfSize:font_spec.size
weight:ToNSFontWeight(font_spec.weight)];
return [font_manager convertFont:font toHaveTrait:traits];
} else {
font = [NSFont systemFontOfSize:font_spec.size];
if (font_spec.weight >= Weight::BOLD)
traits |= NSBoldFontMask;
return [font_manager convertFont:font toHaveTrait:traits];
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -574,12 +412,12 @@ NSFont* PlatformFontMac::NSFontWithSpec(FontSpec font_spec) const { ...@@ -574,12 +412,12 @@ NSFont* PlatformFontMac::NSFontWithSpec(FontSpec font_spec) const {
// static // static
PlatformFont* PlatformFont::CreateDefault() { PlatformFont* PlatformFont::CreateDefault() {
return new PlatformFontMac(PlatformFontMac::SystemFontType::kGeneral); return new PlatformFontMac;
} }
// static // static
PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) { PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
return new PlatformFontMac(native_font); return new PlatformFontMac(ValidateFont(native_font));
} }
// static // static
......
...@@ -7,187 +7,292 @@ ...@@ -7,187 +7,292 @@
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <stddef.h> #include <stddef.h>
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h" #include "ui/gfx/font.h"
// TODO(tapted): Remove gfx:: prefixes.
namespace gfx { namespace gfx {
using Weight = Font::Weight;
TEST(PlatformFontMacTest, DeriveFont) { TEST(PlatformFontMacTest, DeriveFont) {
// |weight_tri| is either -1, 0, or 1 meaning "light", "normal", or "bold".
auto CheckExpected = [](const Font& font, int weight_tri, bool isItalic) {
base::ScopedCFTypeRef<CFDictionaryRef> traits(
CTFontCopyTraits(base::mac::NSToCFCast(font.GetNativeFont())));
DCHECK(traits);
CFNumberRef cf_slant = base::mac::GetValueFromDictionary<CFNumberRef>(
traits, kCTFontSlantTrait);
CGFloat slant;
CFNumberGetValue(cf_slant, kCFNumberCGFloatType, &slant);
if (isItalic)
EXPECT_GT(slant, 0);
else
EXPECT_EQ(slant, 0);
CFNumberRef cf_weight = base::mac::GetValueFromDictionary<CFNumberRef>(
traits, kCTFontWeightTrait);
CGFloat weight;
CFNumberGetValue(cf_weight, kCFNumberCGFloatType, &weight);
if (weight_tri < 0)
EXPECT_LT(weight, 0);
else if (weight_tri == 0)
EXPECT_EQ(weight, 0);
else
EXPECT_GT(weight, 0);
};
// Use a base font that support all traits. // Use a base font that support all traits.
Font base_font("Helvetica", 13); gfx::Font base_font("Helvetica", 13);
{
SCOPED_TRACE("plain font");
CheckExpected(base_font, 0, false);
}
// Italic
Font italic_font(base_font.Derive(0, Font::ITALIC, Weight::NORMAL));
{
SCOPED_TRACE("italic font");
CheckExpected(italic_font, 0, true);
}
// Bold // Bold
Font bold_font(base_font.Derive(0, Font::NORMAL, Weight::BOLD)); gfx::Font bold_font(
{ base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD));
SCOPED_TRACE("bold font"); NSFontTraitMask traits = [[NSFontManager sharedFontManager]
CheckExpected(bold_font, 1, false); traitsOfFont:bold_font.GetNativeFont()];
} EXPECT_EQ(NSBoldFontMask, traits);
// Bold italic
Font bold_italic_font(base_font.Derive(0, Font::ITALIC, Weight::BOLD));
{
SCOPED_TRACE("bold italic font");
CheckExpected(bold_italic_font, 1, true);
}
// Non-existent thin will return the closest weight, light // Italic
Font thin_font(base_font.Derive(0, Font::NORMAL, Weight::THIN)); gfx::Font italic_font(
{ base_font.Derive(0, gfx::Font::ITALIC, gfx::Font::Weight::NORMAL));
SCOPED_TRACE("thin font"); traits = [[NSFontManager sharedFontManager]
CheckExpected(thin_font, -1, false); traitsOfFont:italic_font.GetNativeFont()];
} EXPECT_EQ(NSItalicFontMask, traits);
// Non-existent black will return the closest weight, bold // Bold italic
Font black_font(base_font.Derive(0, Font::NORMAL, Weight::BLACK)); gfx::Font bold_italic_font(
{ base_font.Derive(0, gfx::Font::ITALIC, gfx::Font::Weight::BOLD));
SCOPED_TRACE("black font"); traits = [[NSFontManager sharedFontManager]
CheckExpected(black_font, 1, false); traitsOfFont:bold_italic_font.GetNativeFont()];
} EXPECT_EQ(static_cast<NSFontTraitMask>(NSBoldFontMask | NSItalicFontMask),
traits);
} }
TEST(PlatformFontMacTest, DeriveFontUnderline) { TEST(PlatformFontMacTest, DeriveFontUnderline) {
// Create a default font. // Create a default font.
Font base_font; gfx::Font base_font;
// Make the font underlined. // Make the font underlined.
Font derived_font(base_font.Derive(0, base_font.GetStyle() | Font::UNDERLINE, gfx::Font derived_font(base_font.Derive(
base_font.GetWeight())); 0, base_font.GetStyle() | gfx::Font::UNDERLINE, base_font.GetWeight()));
// Validate the derived font properties against its native font instance. // Validate the derived font properties against its native font instance.
NSFontTraitMask traits = [[NSFontManager sharedFontManager] NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:derived_font.GetNativeFont()]; traitsOfFont:derived_font.GetNativeFont()];
Weight actual_weight = gfx::Font::Weight actual_weight = (traits & NSFontBoldTrait)
(traits & NSFontBoldTrait) ? Weight::BOLD : Weight::NORMAL; ? gfx::Font::Weight::BOLD
: gfx::Font::Weight::NORMAL;
int actual_style = Font::UNDERLINE; int actual_style = gfx::Font::UNDERLINE;
if (traits & NSFontItalicTrait) if (traits & NSFontItalicTrait)
actual_style |= Font::ITALIC; actual_style |= gfx::Font::ITALIC;
EXPECT_TRUE(derived_font.GetStyle() & Font::UNDERLINE); EXPECT_TRUE(derived_font.GetStyle() & gfx::Font::UNDERLINE);
EXPECT_EQ(derived_font.GetStyle(), actual_style); EXPECT_EQ(derived_font.GetStyle(), actual_style);
EXPECT_EQ(derived_font.GetWeight(), actual_weight); EXPECT_EQ(derived_font.GetWeight(), actual_weight);
} }
// Tests internal methods for extracting Font properties from the // Tests internal methods for extracting gfx::Font properties from the
// underlying CTFont representation. // underlying CTFont representation.
TEST(PlatformFontMacTest, ConstructFromNativeFont) { TEST(PlatformFontMacTest, ConstructFromNativeFont) {
Font light_font([NSFont fontWithName:@"Helvetica-Light" size:12]);
EXPECT_EQ(12, light_font.GetFontSize());
EXPECT_EQ("Helvetica", light_font.GetFontName());
EXPECT_EQ(Font::NORMAL, light_font.GetStyle());
EXPECT_EQ(Weight::LIGHT, light_font.GetWeight());
Font light_italic_font([NSFont fontWithName:@"Helvetica-LightOblique"
size:14]);
EXPECT_EQ(14, light_italic_font.GetFontSize());
EXPECT_EQ("Helvetica", light_italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, light_italic_font.GetStyle());
EXPECT_EQ(Weight::LIGHT, light_italic_font.GetWeight());
Font normal_font([NSFont fontWithName:@"Helvetica" size:12]); Font normal_font([NSFont fontWithName:@"Helvetica" size:12]);
EXPECT_EQ(12, normal_font.GetFontSize()); EXPECT_EQ(12, normal_font.GetFontSize());
EXPECT_EQ("Helvetica", normal_font.GetFontName()); EXPECT_EQ("Helvetica", normal_font.GetFontName());
EXPECT_EQ(Font::NORMAL, normal_font.GetStyle()); EXPECT_EQ(Font::NORMAL, normal_font.GetStyle());
EXPECT_EQ(Weight::NORMAL, normal_font.GetWeight()); EXPECT_EQ(Font::Weight::NORMAL, normal_font.GetWeight());
Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]);
EXPECT_EQ(14, bold_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_font.GetFontName());
EXPECT_EQ(Font::NORMAL, bold_font.GetStyle());
EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight());
Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]); Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]);
EXPECT_EQ(14, italic_font.GetFontSize()); EXPECT_EQ(14, italic_font.GetFontSize());
EXPECT_EQ("Helvetica", italic_font.GetFontName()); EXPECT_EQ("Helvetica", italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, italic_font.GetStyle()); EXPECT_EQ(Font::ITALIC, italic_font.GetStyle());
EXPECT_EQ(Weight::NORMAL, italic_font.GetWeight()); EXPECT_EQ(Font::Weight::NORMAL, italic_font.GetWeight());
Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:12]);
EXPECT_EQ(12, bold_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_font.GetFontName());
EXPECT_EQ(Font::NORMAL, bold_font.GetStyle());
EXPECT_EQ(Weight::BOLD, bold_font.GetWeight());
Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]); Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]);
EXPECT_EQ(14, bold_italic_font.GetFontSize()); EXPECT_EQ(14, bold_italic_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_italic_font.GetFontName()); EXPECT_EQ("Helvetica", bold_italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle()); EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle());
EXPECT_EQ(Weight::BOLD, bold_italic_font.GetWeight()); EXPECT_EQ(Font::Weight::BOLD, bold_italic_font.GetWeight());
}
// Specific test for the mapping from the NSFont weight API to gfx::Font::Weight
// values.
TEST(PlatformFontMacTest, FontWeightAPIConsistency) {
// Vanilla Helvetica only has bold and normal, so use a system font.
NSFont* ns_font = [NSFont systemFontOfSize:13];
NSFontManager* manager = [NSFontManager sharedFontManager];
// -[NSFontManager convertWeight:ofFont] supposedly steps the font up and down
// in weight values according to a table at
// https://developer.apple.com/reference/appkit/nsfontmanager/1462321-convertweight
// Apple Terminology | ISO Equivalent
// 1. ultralight | none
// 2. thin | W1. ultralight
// 3. light, extralight | W2. extralight
// 4. book | W3. light
// 5. regular, plain, display, roman | W4. semilight
// 6. medium | W5. medium
// 7. demi, demibold | none
// 8. semi, semibold | W6. semibold
// 9. bold | W7. bold
// 10. extra, extrabold | W8. extrabold
// 11. heavy, heavyface | none
// 12. black, super | W9. ultrabold
// 13. ultra, ultrablack, fat | none
// 14. extrablack, obese, nord | none
EXPECT_EQ(Font::Weight::NORMAL, Font(ns_font).GetWeight()); // Row 5.
// Ensure the Bold "symbolic" trait from the NSFont traits API maps correctly
// to the weight (non-symbolic) trait from the CTFont API.
NSFont* bold_ns_font =
[manager convertFont:ns_font toHaveTrait:NSFontBoldTrait];
Font bold_font(bold_ns_font);
EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight());
// No thin fonts on the lower rows of the table for San Francisco or earlier
// system fonts.
BOOL down = NO;
ns_font = [NSFont systemFontOfSize:13];
for (int row = 4; row > 0; --row) {
SCOPED_TRACE(testing::Message() << "Row: " << row);
ns_font = [manager convertWeight:down ofFont:ns_font];
EXPECT_EQ(Font::Weight::NORMAL, Font(ns_font).GetWeight());
}
BOOL up = YES;
// That is... unless we first go up by one and then down. A LIGHT and a THIN
// font reveal themselves somehow. Only tested on 10.12.
if (base::mac::IsAtLeastOS10_12()) {
ns_font = [NSFont systemFontOfSize:13];
ns_font = [manager convertWeight:up ofFont:ns_font];
ns_font = [manager convertWeight:down ofFont:ns_font];
EXPECT_EQ(Font::Weight::LIGHT, Font(ns_font).GetWeight());
ns_font = [manager convertWeight:down ofFont:ns_font];
EXPECT_EQ(Font::Weight::THIN, Font(ns_font).GetWeight());
}
ns_font = [NSFont systemFontOfSize:13];
if (base::mac::IsOS10_11()) {
// On 10.11 the API jumps to BOLD, but has heavier weights as well.
ns_font = [manager convertWeight:up ofFont:ns_font];
EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight());
ns_font = [manager convertWeight:up ofFont:ns_font];
EXPECT_EQ(Font::Weight::EXTRA_BOLD, Font(ns_font).GetWeight());
ns_font = [manager convertWeight:up ofFont:ns_font];
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight());
return;
}
// Each typeface maps weight notches differently, and the weight is actually a
// floating point value that may not map directly to a gfx::Font::Weight. For
// example San Francisco on macOS 10.12 goes up from 0 in the sequence: [0.23,
// 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] and has no "thin" weights. But also
// iterating over weights does weird stuff sometimes - before macOS 10.15,
// occasionally the font goes italic, but going up another step goes back to
// non-italic, at a heavier weight.
// NSCTFontUIUsageAttribute = CTFontMediumUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23.
EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 6.
// 10.15 fixed the bug where the step up from medium created a medium italic.
if (base::mac::IsAtMostOS10_14()) {
// Goes italic: NSCTFontUIUsageAttribute = CTFontMediumItalicUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23.
EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 7.
}
// NSCTFontUIUsageAttribute = CTFontDemiUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.3.
if (base::mac::IsOS10_10()) {
// 10.10 is Helvetica Neue. It only has NORMAL, MEDIUM, BOLD and BLACK.
EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 8.
} else {
EXPECT_EQ(Font::Weight::SEMIBOLD, Font(ns_font).GetWeight()); // Row 8.
}
// NSCTFontUIUsageAttribute = CTFontEmphasizedUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.4 on 10.11+.
if (base::mac::IsOS10_10()) {
// Remaining rows are all BLACK on 10.10.
for (int row = 9; row <= 14; ++row) {
SCOPED_TRACE(testing::Message() << "Row: " << row);
ns_font = [manager convertWeight:up ofFont:ns_font];
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight());
}
return;
}
EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 9.
// NSCTFontUIUsageAttribute = CTFontHeavyUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.56.
EXPECT_EQ(Font::Weight::EXTRA_BOLD, Font(ns_font).GetWeight()); // Row 10.
// NSCTFontUIUsageAttribute = CTFontBlackUsage.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62.
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 11.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62.
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 12.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62.
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 13.
ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62.
EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 14.
} }
// Test font derivation for fine-grained font weights. // Test font derivation for fine-grained font weights.
TEST(PlatformFontMacTest, DerivedFineGrainedFonts) { TEST(PlatformFontMacTest, DerivedFineGrainedFonts) {
// Only test where San Francisco is available.
if (base::mac::IsAtMostOS10_10())
return;
using Weight = Font::Weight;
// The resulting, actual font weight after deriving |weight| from |base|. // The resulting, actual font weight after deriving |weight| from |base|.
auto DerivedIntWeight = [](Weight weight) { auto DerivedIntWeight = [](const Font& base, Weight weight) {
Font base; // The default system font.
Font derived(base.Derive(0, 0, weight)); Font derived(base.Derive(0, 0, weight));
// PlatformFont should always pass the requested weight, not what the OS // PlatformFont should always pass the requested weight, not what the OS
// could provide. This just checks a constructor argument, so not very // could provide. This just checks a constructor argument, so not very
// interesting. // interesting.
EXPECT_EQ(static_cast<int>(weight), static_cast<int>(derived.GetWeight())); EXPECT_EQ(static_cast<int>(weight), static_cast<int>(derived.GetWeight()));
return static_cast<int>(PlatformFontMac::GetFontWeightFromNSFontForTesting( // Return the weight int value that PlatformFontMac internally derives from
derived.GetNativeFont())); // the floating point weight given by the kCTFontWeightTrait of |font|. Do
// this by creating a new font based only off the NSFont in |derived|.
return static_cast<int>(Font(derived.GetNativeFont()).GetWeight());
}; };
EXPECT_EQ(static_cast<int>(Weight::THIN), DerivedIntWeight(Weight::THIN)); // Only use NORMAL or BOLD as a base font. Mac font APIs go wacky otherwise.
EXPECT_EQ(static_cast<int>(Weight::EXTRA_LIGHT), // See comments in PlatformFontMac::DeriveFont().
DerivedIntWeight(Weight::EXTRA_LIGHT)); Font base([NSFont systemFontOfSize:13]);
EXPECT_EQ(static_cast<int>(Weight::LIGHT), DerivedIntWeight(Weight::LIGHT)); for (Weight base_weight : {Weight::NORMAL, Weight::BOLD}) {
EXPECT_EQ(static_cast<int>(Weight::NORMAL), DerivedIntWeight(Weight::NORMAL)); SCOPED_TRACE(testing::Message()
EXPECT_EQ(static_cast<int>(Weight::MEDIUM), DerivedIntWeight(Weight::MEDIUM)); << "BaseWeight: " << static_cast<int>(base_weight));
if (base::mac::IsAtMostOS10_10()) { if (base_weight != Weight::NORMAL) {
// If a SEMIBOLD system font is requested, 10.10 will return the bold system base = base.Derive(0, 0, base_weight);
// font, but somehow bearing a weight number of 0.24, which is really a EXPECT_EQ(static_cast<int>(base_weight),
// medium weight (0.23). static_cast<int>(base.GetWeight()));
}
// Normal and heavy weights map correctly on 10.11 and 10.12.
EXPECT_EQ(static_cast<int>(Weight::NORMAL),
DerivedIntWeight(base, Weight::NORMAL));
EXPECT_EQ(static_cast<int>(Weight::BOLD),
DerivedIntWeight(base, Weight::BOLD));
EXPECT_EQ(static_cast<int>(Weight::EXTRA_BOLD),
DerivedIntWeight(base, Weight::EXTRA_BOLD));
EXPECT_EQ(static_cast<int>(Weight::BLACK),
DerivedIntWeight(base, Weight::BLACK));
if (base::mac::IsAtMostOS10_11()) {
// The fine-grained font weights on 10.11 are incomplete.
EXPECT_EQ(static_cast<int>(Weight::NORMAL),
DerivedIntWeight(base, Weight::THIN));
EXPECT_EQ(static_cast<int>(Weight::NORMAL),
DerivedIntWeight(base, Weight::EXTRA_LIGHT));
EXPECT_EQ(static_cast<int>(Weight::NORMAL),
DerivedIntWeight(base, Weight::LIGHT));
EXPECT_EQ(static_cast<int>(Weight::BOLD),
DerivedIntWeight(base, Weight::MEDIUM));
EXPECT_EQ(static_cast<int>(Weight::BOLD),
DerivedIntWeight(base, Weight::SEMIBOLD));
continue;
}
// San Francisco doesn't offer anything between THIN and LIGHT.
EXPECT_EQ(static_cast<int>(Weight::THIN),
DerivedIntWeight(base, Weight::EXTRA_LIGHT));
// All the rest should map correctly.
EXPECT_EQ(static_cast<int>(Weight::THIN),
DerivedIntWeight(base, Weight::THIN));
EXPECT_EQ(static_cast<int>(Weight::LIGHT),
DerivedIntWeight(base, Weight::LIGHT));
EXPECT_EQ(static_cast<int>(Weight::MEDIUM), EXPECT_EQ(static_cast<int>(Weight::MEDIUM),
DerivedIntWeight(Weight::SEMIBOLD)); DerivedIntWeight(base, Weight::MEDIUM));
} else {
EXPECT_EQ(static_cast<int>(Weight::SEMIBOLD), EXPECT_EQ(static_cast<int>(Weight::SEMIBOLD),
DerivedIntWeight(Weight::SEMIBOLD)); DerivedIntWeight(base, Weight::SEMIBOLD));
} }
EXPECT_EQ(static_cast<int>(Weight::BOLD), DerivedIntWeight(Weight::BOLD));
EXPECT_EQ(static_cast<int>(Weight::EXTRA_BOLD),
DerivedIntWeight(Weight::EXTRA_BOLD));
EXPECT_EQ(static_cast<int>(Weight::BLACK), DerivedIntWeight(Weight::BLACK));
} }
// Ensures that the Font's reported height is consistent with the native font's // Ensures that the Font's reported height is consistent with the native font's
...@@ -195,14 +300,16 @@ TEST(PlatformFontMacTest, DerivedFineGrainedFonts) { ...@@ -195,14 +300,16 @@ TEST(PlatformFontMacTest, DerivedFineGrainedFonts) {
TEST(PlatformFontMacTest, ValidateFontHeight) { TEST(PlatformFontMacTest, ValidateFontHeight) {
// Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10, // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10,
// Lucida Grande before that, and San Francisco after. // Lucida Grande before that, and San Francisco after.
Font default_font; gfx::Font default_font;
Font::FontStyle styles[] = {Font::NORMAL, Font::ITALIC, Font::UNDERLINE}; gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC,
gfx::Font::UNDERLINE};
for (size_t i = 0; i < base::size(styles); ++i) { for (size_t i = 0; i < base::size(styles); ++i) {
SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << styles[i]); SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << styles[i]);
// Include the range of sizes used by ResourceBundle::FontStyle (-1 to +8). // Include the range of sizes used by ResourceBundle::FontStyle (-1 to +8).
for (int delta = -1; delta <= 8; ++delta) { for (int delta = -1; delta <= 8; ++delta) {
Font font = default_font.Derive(delta, styles[i], Weight::NORMAL); gfx::Font font =
default_font.Derive(delta, styles[i], gfx::Font::Weight::NORMAL);
SCOPED_TRACE(testing::Message() << "FontSize(): " << font.GetFontSize()); SCOPED_TRACE(testing::Message() << "FontSize(): " << font.GetFontSize());
NSFont* native_font = font.GetNativeFont(); NSFont* native_font = font.GetNativeFont();
...@@ -236,14 +343,15 @@ TEST(PlatformFontMacTest, ValidateFontHeight) { ...@@ -236,14 +343,15 @@ TEST(PlatformFontMacTest, ValidateFontHeight) {
// Appkit's bug was detected on macOS 10.10 which uses Helvetica Neue as the // Appkit's bug was detected on macOS 10.10 which uses Helvetica Neue as the
// system font. // system font.
TEST(PlatformFontMacTest, DerivedSemiboldFontIsNotItalic) { TEST(PlatformFontMacTest, DerivedSemiboldFontIsNotItalic) {
Font base_font; gfx::Font base_font;
{ {
NSFontTraitMask traits = [[NSFontManager sharedFontManager] NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:base_font.GetNativeFont()]; traitsOfFont:base_font.GetNativeFont()];
ASSERT_FALSE(traits & NSItalicFontMask); ASSERT_FALSE(traits & NSItalicFontMask);
} }
Font semibold_font(base_font.Derive(0, Font::NORMAL, Weight::SEMIBOLD)); gfx::Font semibold_font(
base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::SEMIBOLD));
NSFontTraitMask traits = [[NSFontManager sharedFontManager] NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:semibold_font.GetNativeFont()]; traitsOfFont:semibold_font.GetNativeFont()];
EXPECT_FALSE(traits & NSItalicFontMask); EXPECT_FALSE(traits & NSItalicFontMask);
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "ui/base/cocoa/cocoa_base_utils.h" #include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/gfx/font_list.h" #include "ui/gfx/font_list.h"
#import "ui/gfx/mac/coordinate_conversion.h" #import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/gfx/platform_font_mac.h"
namespace { namespace {
...@@ -33,10 +32,8 @@ int TooltipManagerMac::GetMaxWidth(const gfx::Point& location) const { ...@@ -33,10 +32,8 @@ int TooltipManagerMac::GetMaxWidth(const gfx::Point& location) const {
} }
const gfx::FontList& TooltipManagerMac::GetFontList() const { const gfx::FontList& TooltipManagerMac::GetFontList() const {
static base::NoDestructor<gfx::FontList> font_list([]() { static base::NoDestructor<gfx::FontList> font_list(
return gfx::Font(new gfx::PlatformFontMac( []() { return gfx::Font([NSFont toolTipsFontOfSize:0]); }());
gfx::PlatformFontMac::SystemFontType::kToolTip));
}());
return *font_list; return *font_list;
} }
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#include "ui/gfx/platform_font_mac.h"
namespace { namespace {
...@@ -43,8 +42,7 @@ void InitMaterialMenuConfig(views::MenuConfig* config) { ...@@ -43,8 +42,7 @@ void InitMaterialMenuConfig(views::MenuConfig* config) {
namespace views { namespace views {
void MenuConfig::Init() { void MenuConfig::Init() {
font_list = gfx::FontList(gfx::Font( font_list = gfx::FontList(gfx::Font([NSFont menuFontOfSize:0.0]));
new gfx::PlatformFontMac(gfx::PlatformFontMac::SystemFontType::kMenu)));
check_selected_combobox_item = true; check_selected_combobox_item = true;
arrow_key_selection_wraps = false; arrow_key_selection_wraps = false;
use_mnemonics = false; use_mnemonics = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment