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 @@
#include "base/compiler_specific.h"
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "base/optional.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/platform_font.h"
namespace gfx {
class GFX_EXPORT PlatformFontMac : public PlatformFont {
class PlatformFontMac : public PlatformFont {
public:
// An enum indicating a type of system-specified font.
// - 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.
PlatformFontMac();
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,
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,
int font_size_pixels,
const base::Optional<FontRenderParams>& params);
......@@ -62,44 +41,35 @@ class GFX_EXPORT PlatformFontMac : public PlatformFont {
NativeFont GetNativeFont() 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:
struct FontSpec {
std::string name; // Corresponds to -[NSFont fontFamily].
int size;
int style;
Font::Weight weight;
};
PlatformFontMac(NativeFont font,
base::Optional<SystemFontType> system_font_type);
PlatformFontMac(const std::string& font_name,
int font_size,
int font_style,
Font::Weight font_weight);
PlatformFontMac(NativeFont font,
base::Optional<SystemFontType> system_font_type,
FontSpec spec);
const std::string& font_name,
int font_size,
int font_style,
Font::Weight font_weight);
~PlatformFontMac() override;
// Calculates and caches the font metrics and initializes |render_params_|.
// Calculates and caches the font metrics and inits |render_params_|.
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
// NSFont instance, this holds that NSFont instance. Otherwise this NSFont
// instance is constructed from the name, size, and style. If there is no
// active font that matched those criteria a default font is used.
base::scoped_nsobject<NSFont> native_font_;
// If the font is a system font, and if so, what kind.
const base::Optional<SystemFontType> system_font_type_;
// The name/size/style/weight quartet that specify the font. Initialized in
// the constructors.
const FontSpec font_spec_;
// The name/size/style trio that specify the font. Initialized in the
// constructors.
const std::string font_name_; // Corresponds to -[NSFont fontFamily].
const int font_size_;
const int font_style_;
const Font::Weight font_weight_;
// Cached metrics, generated in CalculateMetrics().
int height_;
......
......@@ -5,15 +5,12 @@
#include "ui/gfx/platform_font_mac.h"
#include <cmath>
#include <set>
#include <Cocoa/Cocoa.h>
#include "base/bit_cast.h"
#import "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#import "base/mac/scoped_nsobject.h"
#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/ports/SkTypeface_mac.h"
......@@ -23,13 +20,61 @@
namespace gfx {
using Weight = Font::Weight;
namespace {
extern "C" {
bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
}
// How to get from NORMAL weight to a fine-grained font weight using calls to
// -[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
// does not support it as a trait.
......@@ -41,21 +86,21 @@ int GetFontStyleFromNSFont(NSFont* font) {
return font_style;
}
// Returns the Font::Weight for |font|.
Weight GetFontWeightFromNSFont(NSFont* font) {
// Returns the Font weight for |font|.
Font::Weight GetFontWeightFromNSFont(NSFont* font) {
DCHECK(font);
// 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
// system fonts. See PlatformFontMacTest.FontWeightAPIConsistency for details.
// macOS uses specific float values in its constants, but individual fonts can
// and do specify arbitrary values in the -1.0 to 1.0 range. Therefore, to
// accomodate that, and to avoid float comparison issues, use ranges.
// The Mac uses specific float values, but to avoid float comparison
// inaccuracies as well as for paranoia in case float values other than these
// appear, use ranges.
constexpr struct {
// A range of CoreText weights.
CGFloat weight_lower;
CGFloat weight_upper;
Weight gfx_weight;
Font::Weight gfx_weight;
} weight_map[] = {
// NSFontWeight constants introduced in 10.11:
// NSFontWeightUltraLight: -0.80
......@@ -70,35 +115,29 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
//
// Actual system font weights:
// 10.10:
// .HelveticaNeueDeskInterface-UltraLightP2: -0.80
// .HelveticaNeueDeskInterface-Thin: -0.50
// .HelveticaNeueDeskInterface-Light: -0.425
// .HelveticaNeueDeskInterface-Regular: 0.0
// .HelveticaNeueDeskInterface-MediumP4: 0.23
// .HelveticaNeueDeskInterface-Bold (if requested as semibold): 0.24
// .HelveticaNeueDeskInterface-Bold (if requested as bold): 0.4
// .HelveticaNeueDeskInterface-Heavy (if requested as heavy): 0.576
// .HelveticaNeueDeskInterface-Heavy (if requested as black): 0.662
// .HelveticaNeueDeskInterface-Bold: 0.4
// .HelveticaNeueDeskInterface-Heavy: 0.62
// 10.11-:
// .AppleSystemUIFontUltraLight: -0.80
// .AppleSystemUIFontThin: -0.60
// .AppleSystemUIFontLight: -0.40
// .AppleSystemUIFont: 0.0
// .AppleSystemUIFontMedium: 0.23
// .AppleSystemUIFontDemi: 0.30
// .AppleSystemUIFontBold (10.11): 0.40
// .AppleSystemUIFontEmphasized (10.12-): 0.40
// .AppleSystemUIFontHeavy: 0.56
// .AppleSystemUIFontBlack: 0.62
{-1.0, -0.70, Weight::THIN}, // NSFontWeightUltraLight
{-0.70, -0.45, Weight::EXTRA_LIGHT}, // NSFontWeightThin
{-0.45, -0.10, Weight::LIGHT}, // NSFontWeightLight
{-0.10, 0.10, Weight::NORMAL}, // NSFontWeightRegular
{0.10, 0.27, Weight::MEDIUM}, // NSFontWeightMedium
{0.27, 0.35, Weight::SEMIBOLD}, // NSFontWeightSemibold
{0.35, 0.50, Weight::BOLD}, // NSFontWeightBold
{0.50, 0.60, Weight::EXTRA_BOLD}, // NSFontWeightHeavy
{0.60, 1.0, Weight::BLACK}, // NSFontWeightBlack
// .AppleSystemUIFontUltraLight: -0.80 (10.12-)
// .AppleSystemUIFontLight: -0.40 (10.12-)
// .AppleSystemUIFont: 0 (10.11-)
// .AppleSystemUIFontMedium: 0.23 (10.12-)
// .AppleSystemUIFontDemi: 0.30 (10.12-)
// .AppleSystemUIFontBold: 0.40 (10.11)
// .AppleSystemUIFontEmphasized: 0.40 (10.12-)
// .AppleSystemUIFontHeavy: 0.56 (10.11-)
// .AppleSystemUIFontBlack: 0.62 (10.11-)
{-1.0, -0.70, Font::Weight::THIN}, // NSFontWeightUltraLight
{-0.70, -0.45, Font::Weight::EXTRA_LIGHT}, // NSFontWeightThin
{-0.45, -0.10, Font::Weight::LIGHT}, // NSFontWeightLight
{-0.10, 0.10, Font::Weight::NORMAL}, // NSFontWeightRegular
{0.10, 0.27, Font::Weight::MEDIUM}, // NSFontWeightMedium
{0.27, 0.35, Font::Weight::SEMIBOLD}, // NSFontWeightSemibold
{0.35, 0.50, Font::Weight::BOLD}, // NSFontWeightBold
{0.50, 0.60, Font::Weight::EXTRA_BOLD}, // NSFontWeightHeavy
{0.60, 1.0, Font::Weight::BLACK}, // NSFontWeightBlack
};
base::ScopedCFTypeRef<CFDictionaryRef> traits(
......@@ -108,7 +147,7 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
traits, kCTFontWeightTrait);
// A missing weight attribute just means 0 -> NORMAL.
if (!cf_weight)
return Weight::NORMAL;
return Font::Weight::NORMAL;
// The value of kCTFontWeightTrait empirically is a kCFNumberFloat64Type
// (double) on all tested versions of macOS. However, that doesn't really
......@@ -121,116 +160,47 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
if (item.weight_lower <= weight && weight <= item.weight_upper)
return item.gfx_weight;
}
return Weight::INVALID;
return Font::Weight::INVALID;
}
// Converts a Font::Weight value to the corresponding NSFontWeight value.
NSFontWeight ToNSFontWeight(Weight weight) {
if (@available(macOS 10.11, *)) {
switch (weight) {
case Weight::THIN:
return NSFontWeightUltraLight;
case Weight::EXTRA_LIGHT:
return NSFontWeightThin;
case Weight::LIGHT:
return NSFontWeightLight;
case Weight::INVALID:
case Weight::NORMAL:
return NSFontWeightRegular;
case Weight::MEDIUM:
return NSFontWeightMedium;
case Weight::SEMIBOLD:
return NSFontWeightSemibold;
case Weight::BOLD:
return NSFontWeightBold;
case Weight::EXTRA_BOLD:
return NSFontWeightHeavy;
case Weight::BLACK:
return NSFontWeightBlack;
}
} else {
// See third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm.
uint64_t int_value = 0;
switch (weight) {
case Weight::THIN:
int_value = 0xbfe99999a0000000; // NSFontWeightUltraLight;
break;
case Weight::EXTRA_LIGHT:
int_value = 0xbfe3333340000000; // NSFontWeightThin;
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);
}
// Returns an autoreleased NSFont created with the passed-in specifications.
NSFont* NSFontWithSpec(const std::string& font_name,
int font_size,
int font_style,
Font::Weight font_weight) {
NSFontSymbolicTraits trait_bits = 0;
// TODO(mboc): Add support for other weights as well.
if (font_weight >= Font::Weight::BOLD)
trait_bits |= NSFontBoldTrait;
if (font_style & Font::ITALIC)
trait_bits |= NSFontItalicTrait;
// The Mac doesn't support underline as a font trait, so just drop it.
// (Underlines must be added as an attribute on an NSAttributedString.)
NSDictionary* traits = @{ NSFontSymbolicTrait : @(trait_bits) };
NSDictionary* attrs = @{
NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name),
NSFontTraitsAttribute : traits
};
NSFontDescriptor* descriptor =
[NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size];
if (font)
return font;
// Make one fallback attempt by looking up via font name rather than font
// family name.
attrs = @{
NSFontNameAttribute : base::SysUTF8ToNSString(font_name),
NSFontTraitsAttribute : traits
};
descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
return [NSFont fontWithDescriptor:descriptor size:font_size];
}
// Chromium uses the ISO-style, 9-value ladder of font weights (THIN-BLACK). The
// new font API in macOS also uses these weights, though they are constants
// defined in terms of CGFloat with values from -1.0 to 1.0.
//
// 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;
}
// Returns |font| or a default font if |font| is nil.
NSFont* ValidateFont(NSFont* font) {
return font ? font : [NSFont systemFontOfSize:[NSFont systemFontSize]];
}
std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) {
......@@ -239,155 +209,88 @@ std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) {
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
////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, public:
PlatformFontMac::PlatformFontMac(SystemFontType system_font_type)
: PlatformFontMac(SystemFontForConstructorOfType(system_font_type),
system_font_type) {}
PlatformFontMac::PlatformFontMac()
: PlatformFontMac([NSFont systemFontOfSize:[NSFont systemFontSize]]) {
}
PlatformFontMac::PlatformFontMac(NativeFont native_font)
: PlatformFontMac(native_font, base::nullopt) {
DCHECK(native_font); // nil should not be passed to this constructor.
: PlatformFontMac(native_font,
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(
NSFontWithSpec({font_name, font_size, Font::NORMAL, Weight::NORMAL}),
base::nullopt,
{font_name, font_size, Font::NORMAL, Weight::NORMAL}) {}
: PlatformFontMac(font_name,
font_size,
Font::NORMAL,
Font::Weight::NORMAL) {}
PlatformFontMac::PlatformFontMac(sk_sp<SkTypeface> typeface,
int font_size_pixels,
const base::Optional<FontRenderParams>& params)
: PlatformFontMac(
base::mac::CFToNSCast(SkTypeface_GetCTFontRef(typeface.get())),
SystemFontTypeFromUndocumentedCTFontRefInternals(
SkTypeface_GetCTFontRef(typeface.get())),
{GetFamilyNameFromTypeface(typeface), font_size_pixels,
(typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
FontWeightFromInt(typeface->fontStyle().weight())}) {}
GetFamilyNameFromTypeface(typeface),
font_size_pixels,
(typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
FontWeightFromInt(typeface->fontStyle().weight())) {}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, PlatformFont implementation:
Font PlatformFontMac::DeriveFont(int size_delta,
int style,
Weight weight) const {
// What doesn't work?
//
// For all fonts, -[NSFontManager convertWeight:ofFont:] will reliably
// misbehave, skipping over particular weights of fonts, refusing to go
// lighter than regular unless you go heavier first, and in earlier versions
// of the system would accidentally introduce italic fonts when changing
// weights from a non-italic instance.
//
// For system fonts, -[NSFontManager convertFont:to(Not)HaveTrait:], if used
// to change weight, will sometimes switch to a compatibility system font that
// does not have all the weights available.
//
// For system fonts, the most reliable call to use is +[NSFont
// systemFontOfSize:weight:]. This uses the new-style NSFontWeight which maps
// perfectly to the ISO weights that Chromium uses. For non-system fonts,
// -[NSFontManager fontWithFamily:traits:weight:size:] is the only reasonable
// way to query fonts with more granularity than bold/non-bold short of
// walking the font family and querying their kCTFontWeightTrait values. Font
// descriptors hold promise but querying using them often fails to find fonts
// that match; hopefully their matching abilities will improve in future
// versions of the macOS.
if (system_font_type_ == SystemFontType::kGeneral) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
// +[NSFont systemFontOfSize:weight:] is declared as available on 10.11+,
// but actually it is there and works on 10.10.
NSFont* derived = [NSFont systemFontOfSize:font_spec_.size + size_delta
weight:ToNSFontWeight(weight)];
#pragma clang diagnostic pop
Font::Weight weight) const {
// For some reason, creating fonts using the NSFontDescriptor API's seem to be
// unreliable. Hence use the NSFontManager.
NSFont* derived = native_font_;
NSFontManager* font_manager = [NSFontManager sharedFontManager];
if (weight != font_weight_) {
// Find a font without any bold traits. Ideally, all bold traits are
// removed here, but non-symbolic traits are read-only properties of a
// particular set of glyphs. And attempting to "reset" the attribute with a
// new font descriptor will lose internal properties that Mac decorates its
// UI fonts with. E.g., solving the plans below from NORMAL result in a
// CTFontDescriptor attribute entry of NSCTFontUIUsageAttribute in
// CTFont{Regular,Medium,Demi,Emphasized,Heavy,Black}Usage. Attempting to
// "solve" weights starting at other than NORMAL has unpredictable results.
if (font_weight_ != Font::Weight::NORMAL)
derived = [font_manager convertFont:derived toHaveTrait:NSUnboldFontMask];
DLOG_IF(WARNING, GetFontWeightFromNSFont(derived) != Font::Weight::NORMAL)
<< "Deriving from a font with an internal unmodifiable weight.";
WeightSolver plan = WeightChangeFromNormal(weight);
if (plan.nearest == Font::Weight::BOLD)
derived = [font_manager convertFont:derived toHaveTrait:NSBoldFontMask];
for (int i = 0; i < plan.steps_up; ++i)
derived = [font_manager convertWeight:YES ofFont:derived];
for (int i = 0; i < plan.steps_down; ++i)
derived = [font_manager convertWeight:NO ofFont:derived];
}
// Always apply the italic trait, even if the italic trait is not changing.
// 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 =
(style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask;
derived = [[NSFontManager sharedFontManager] convertFont:derived
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}));
derived = [font_manager convertFont:derived toHaveTrait:italic_trait_mask];
}
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() {
......@@ -420,15 +323,15 @@ int PlatformFontMac::GetExpectedTextWidth(int length) {
}
int PlatformFontMac::GetStyle() const {
return font_spec_.style;
return font_style_;
}
Weight PlatformFontMac::GetWeight() const {
return font_spec_.weight;
Font::Weight PlatformFontMac::GetWeight() const {
return font_weight_;
}
const std::string& PlatformFontMac::GetFontName() const {
return font_spec_.name;
return font_name_;
}
std::string PlatformFontMac::GetActualFontName() const {
......@@ -436,7 +339,7 @@ std::string PlatformFontMac::GetActualFontName() const {
}
int PlatformFontMac::GetFontSize() const {
return font_spec_.size;
return font_size_;
}
const FontRenderParams& PlatformFontMac::GetFontRenderParams() {
......@@ -451,35 +354,30 @@ sk_sp<SkTypeface> PlatformFontMac::GetNativeSkTypeface() const {
return SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(GetNativeFont()));
}
// static
Weight PlatformFontMac::GetFontWeightFromNSFontForTesting(NSFont* font) {
return GetFontWeightFromNSFont(font);
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, private:
PlatformFontMac::PlatformFontMac(
NativeFont font,
base::Optional<SystemFontType> system_font_type)
PlatformFontMac::PlatformFontMac(const std::string& font_name,
int font_size,
int font_style,
Font::Weight font_weight)
: PlatformFontMac(
font,
system_font_type,
{base::SysNSStringToUTF8([font familyName]), [font pointSize],
GetFontStyleFromNSFont(font), GetFontWeightFromNSFont(font)}) {}
PlatformFontMac::PlatformFontMac(
NativeFont font,
base::Optional<SystemFontType> system_font_type,
FontSpec spec)
: native_font_([font retain]),
system_font_type_(system_font_type),
font_spec_(spec) {
DCHECK(system_font_type.has_value() ||
SystemFontNames().count(spec.name) == 0)
<< "Do not pass a system font (" << spec.name << ") to PlatformFontMac; "
<< "use the SystemFontType constructor. Extend the SystemFontType enum "
<< "if necessary.";
NSFontWithSpec(font_name, font_size, font_style, font_weight),
font_name,
font_size,
font_style,
font_weight) {}
PlatformFontMac::PlatformFontMac(NativeFont font,
const std::string& font_name,
int font_size,
int font_style,
Font::Weight font_weight)
: native_font_([ValidateFont(font) retain]),
font_name_(font_name),
font_size_(font_size),
font_style_(font_style),
font_weight_(font_weight) {
CalculateMetricsAndInitRenderParams();
}
......@@ -502,71 +400,11 @@ void PlatformFontMac::CalculateMetricsAndInitRenderParams() {
height_ = ceil(ascent_ + std::abs([font descender]) + [font leading]);
FontRenderParamsQuery query;
query.families.push_back(font_spec_.name);
query.pixel_size = font_spec_.size;
query.style = font_spec_.style;
query.weight = font_spec_.weight;
render_params_ = gfx::GetFontRenderParams(query, nullptr);
}
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];
}
query.families.push_back(font_name_);
query.pixel_size = font_size_;
query.style = font_style_;
query.weight = font_weight_;
render_params_ = gfx::GetFontRenderParams(query, NULL);
}
////////////////////////////////////////////////////////////////////////////////
......@@ -574,12 +412,12 @@ NSFont* PlatformFontMac::NSFontWithSpec(FontSpec font_spec) const {
// static
PlatformFont* PlatformFont::CreateDefault() {
return new PlatformFontMac(PlatformFontMac::SystemFontType::kGeneral);
return new PlatformFontMac;
}
// static
PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
return new PlatformFontMac(native_font);
return new PlatformFontMac(ValidateFont(native_font));
}
// static
......
......@@ -7,187 +7,292 @@
#include <Cocoa/Cocoa.h>
#include <stddef.h>
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
// TODO(tapted): Remove gfx:: prefixes.
namespace gfx {
using Weight = Font::Weight;
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.
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);
}
gfx::Font base_font("Helvetica", 13);
// Bold
Font bold_font(base_font.Derive(0, Font::NORMAL, Weight::BOLD));
{
SCOPED_TRACE("bold font");
CheckExpected(bold_font, 1, false);
}
// 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);
}
gfx::Font bold_font(
base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD));
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_font.GetNativeFont()];
EXPECT_EQ(NSBoldFontMask, traits);
// Non-existent thin will return the closest weight, light
Font thin_font(base_font.Derive(0, Font::NORMAL, Weight::THIN));
{
SCOPED_TRACE("thin font");
CheckExpected(thin_font, -1, false);
}
// Italic
gfx::Font italic_font(
base_font.Derive(0, gfx::Font::ITALIC, gfx::Font::Weight::NORMAL));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:italic_font.GetNativeFont()];
EXPECT_EQ(NSItalicFontMask, traits);
// Non-existent black will return the closest weight, bold
Font black_font(base_font.Derive(0, Font::NORMAL, Weight::BLACK));
{
SCOPED_TRACE("black font");
CheckExpected(black_font, 1, false);
}
// Bold italic
gfx::Font bold_italic_font(
base_font.Derive(0, gfx::Font::ITALIC, gfx::Font::Weight::BOLD));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_italic_font.GetNativeFont()];
EXPECT_EQ(static_cast<NSFontTraitMask>(NSBoldFontMask | NSItalicFontMask),
traits);
}
TEST(PlatformFontMacTest, DeriveFontUnderline) {
// Create a default font.
Font base_font;
gfx::Font base_font;
// Make the font underlined.
Font derived_font(base_font.Derive(0, base_font.GetStyle() | Font::UNDERLINE,
base_font.GetWeight()));
gfx::Font derived_font(base_font.Derive(
0, base_font.GetStyle() | gfx::Font::UNDERLINE, base_font.GetWeight()));
// Validate the derived font properties against its native font instance.
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:derived_font.GetNativeFont()];
Weight actual_weight =
(traits & NSFontBoldTrait) ? Weight::BOLD : Weight::NORMAL;
gfx::Font::Weight actual_weight = (traits & NSFontBoldTrait)
? gfx::Font::Weight::BOLD
: gfx::Font::Weight::NORMAL;
int actual_style = Font::UNDERLINE;
int actual_style = gfx::Font::UNDERLINE;
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.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.
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]);
EXPECT_EQ(12, normal_font.GetFontSize());
EXPECT_EQ("Helvetica", normal_font.GetFontName());
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]);
EXPECT_EQ(14, italic_font.GetFontSize());
EXPECT_EQ("Helvetica", italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, italic_font.GetStyle());
EXPECT_EQ(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());
EXPECT_EQ(Font::Weight::NORMAL, italic_font.GetWeight());
Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]);
EXPECT_EQ(14, bold_italic_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_italic_font.GetFontName());
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(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|.
auto DerivedIntWeight = [](Weight weight) {
Font base; // The default system font.
auto DerivedIntWeight = [](const Font& base, Weight weight) {
Font derived(base.Derive(0, 0, weight));
// PlatformFont should always pass the requested weight, not what the OS
// could provide. This just checks a constructor argument, so not very
// interesting.
EXPECT_EQ(static_cast<int>(weight), static_cast<int>(derived.GetWeight()));
return static_cast<int>(PlatformFontMac::GetFontWeightFromNSFontForTesting(
derived.GetNativeFont()));
// Return the weight int value that PlatformFontMac internally derives from
// 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));
EXPECT_EQ(static_cast<int>(Weight::EXTRA_LIGHT),
DerivedIntWeight(Weight::EXTRA_LIGHT));
EXPECT_EQ(static_cast<int>(Weight::LIGHT), DerivedIntWeight(Weight::LIGHT));
EXPECT_EQ(static_cast<int>(Weight::NORMAL), DerivedIntWeight(Weight::NORMAL));
EXPECT_EQ(static_cast<int>(Weight::MEDIUM), DerivedIntWeight(Weight::MEDIUM));
if (base::mac::IsAtMostOS10_10()) {
// If a SEMIBOLD system font is requested, 10.10 will return the bold system
// font, but somehow bearing a weight number of 0.24, which is really a
// medium weight (0.23).
// Only use NORMAL or BOLD as a base font. Mac font APIs go wacky otherwise.
// See comments in PlatformFontMac::DeriveFont().
Font base([NSFont systemFontOfSize:13]);
for (Weight base_weight : {Weight::NORMAL, Weight::BOLD}) {
SCOPED_TRACE(testing::Message()
<< "BaseWeight: " << static_cast<int>(base_weight));
if (base_weight != Weight::NORMAL) {
base = base.Derive(0, 0, base_weight);
EXPECT_EQ(static_cast<int>(base_weight),
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),
DerivedIntWeight(Weight::SEMIBOLD));
} else {
DerivedIntWeight(base, Weight::MEDIUM));
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
......@@ -195,14 +300,16 @@ TEST(PlatformFontMacTest, DerivedFineGrainedFonts) {
TEST(PlatformFontMacTest, ValidateFontHeight) {
// Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10,
// Lucida Grande before that, and San Francisco after.
Font default_font;
Font::FontStyle styles[] = {Font::NORMAL, Font::ITALIC, Font::UNDERLINE};
gfx::Font default_font;
gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC,
gfx::Font::UNDERLINE};
for (size_t i = 0; i < base::size(styles); ++i) {
SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << styles[i]);
// Include the range of sizes used by ResourceBundle::FontStyle (-1 to +8).
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());
NSFont* native_font = font.GetNativeFont();
......@@ -236,14 +343,15 @@ TEST(PlatformFontMacTest, ValidateFontHeight) {
// Appkit's bug was detected on macOS 10.10 which uses Helvetica Neue as the
// system font.
TEST(PlatformFontMacTest, DerivedSemiboldFontIsNotItalic) {
Font base_font;
gfx::Font base_font;
{
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:base_font.GetNativeFont()];
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]
traitsOfFont:semibold_font.GetNativeFont()];
EXPECT_FALSE(traits & NSItalicFontMask);
......
......@@ -10,7 +10,6 @@
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/gfx/font_list.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/gfx/platform_font_mac.h"
namespace {
......@@ -33,10 +32,8 @@ int TooltipManagerMac::GetMaxWidth(const gfx::Point& location) const {
}
const gfx::FontList& TooltipManagerMac::GetFontList() const {
static base::NoDestructor<gfx::FontList> font_list([]() {
return gfx::Font(new gfx::PlatformFontMac(
gfx::PlatformFontMac::SystemFontType::kToolTip));
}());
static base::NoDestructor<gfx::FontList> font_list(
[]() { return gfx::Font([NSFont toolTipsFontOfSize:0]); }());
return *font_list;
}
......
......@@ -7,7 +7,6 @@
#import <AppKit/AppKit.h>
#include "base/mac/mac_util.h"
#include "ui/gfx/platform_font_mac.h"
namespace {
......@@ -43,8 +42,7 @@ void InitMaterialMenuConfig(views::MenuConfig* config) {
namespace views {
void MenuConfig::Init() {
font_list = gfx::FontList(gfx::Font(
new gfx::PlatformFontMac(gfx::PlatformFontMac::SystemFontType::kMenu)));
font_list = gfx::FontList(gfx::Font([NSFont menuFontOfSize:0.0]));
check_selected_combobox_item = true;
arrow_key_selection_wraps = 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