Commit bc62dfea authored by tapted's avatar tapted Committed by Commit bot

Support finer grained font weights on Mac.

We want to explore a MEDIUM weight for button text under Harmony. This
is consistent with MD and helps compensate for buttons not using solid
black for the font color.

The San Francisco font in 10.11 and 10.12 has good support for finer
grained weights and is the font Chrome UI is mostly concerned with, so
focus testing on that but survey expectations for all supported OS
versions.

BUG=691891

Review-Url: https://codereview.chromium.org/2869803005
Cr-Commit-Position: refs/heads/master@{#473457}
parent 3cb12d3b
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h" #import "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#import "base/mac/scoped_nsobject.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 "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
...@@ -19,6 +21,60 @@ namespace gfx { ...@@ -19,6 +21,60 @@ namespace gfx {
namespace { namespace {
// 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;
};
// 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.
int GetFontStyleFromNSFont(NSFont* font) { int GetFontStyleFromNSFont(NSFont* font) {
...@@ -31,8 +87,56 @@ int GetFontStyleFromNSFont(NSFont* font) { ...@@ -31,8 +87,56 @@ int GetFontStyleFromNSFont(NSFont* font) {
// Returns the Font weight for |font|. // Returns the Font weight for |font|.
Font::Weight GetFontWeightFromNSFont(NSFont* font) { Font::Weight GetFontWeightFromNSFont(NSFont* font) {
NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits]; if (!font)
return (traits & NSFontBoldTrait) ? Font::Weight::BOLD : Font::Weight::NORMAL; return Font::Weight::INVALID;
// Map CoreText weights in a manner similar to ct_weight_to_fontstyle() from
// SkFontHost_mac.cpp, but adjust for MEDIUM so that the San Francisco's
// custom MEDIUM weight can be picked out. San Francisco has weights:
// [0.23, 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] (no thin weights).
// See PlatformFontMacTest.FontWeightAPIConsistency for details.
// Note that the table Skia uses is also determined by experiment.
constexpr struct {
CGFloat ct_weight;
Font::Weight gfx_weight;
} weight_map[] = {
// Missing: Apple "ultralight".
{-0.70, Font::Weight::THIN},
{-0.50, Font::Weight::EXTRA_LIGHT},
{-0.23, Font::Weight::LIGHT},
{0.00, Font::Weight::NORMAL},
{0.23, Font::Weight::MEDIUM}, // Note: adjusted from 0.20 vs Skia.
// Missing: Apple "demibold".
{0.30, Font::Weight::SEMIBOLD},
{0.40, Font::Weight::BOLD},
{0.60, Font::Weight::EXTRA_BOLD},
// Missing: Apple "heavyface".
// Values will be capped to BLACK (this entry is here for consistency).
{0.80, Font::Weight::BLACK},
// Missing: Apple "ultrablack".
// Missing: Apple "extrablack".
};
base::ScopedCFTypeRef<CFDictionaryRef> traits(
CTFontCopyTraits(base::mac::NSToCFCast(font)));
DCHECK(traits);
CFNumberRef cf_weight = base::mac::GetValueFromDictionary<CFNumberRef>(
traits, kCTFontWeightTrait);
// A missing weight attribute just means 0 -> NORMAL.
if (!cf_weight)
return Font::Weight::NORMAL;
// Documentation is vague about what sized floating point type should be used.
// However, numeric_limits::epsilon() for 64-bit types is too small to match
// the above table, so use 32-bit float.
float weight_value;
Boolean success =
CFNumberGetValue(cf_weight, kCFNumberFloatType, &weight_value);
DCHECK(success);
for (const auto& item : weight_map) {
if (weight_value - item.ct_weight <= std::numeric_limits<float>::epsilon())
return item.gfx_weight;
}
return Font::Weight::BLACK;
} }
// Returns an autoreleased NSFont created with the passed-in specifications. // Returns an autoreleased NSFont created with the passed-in specifications.
...@@ -100,24 +204,43 @@ Font PlatformFontMac::DeriveFont(int size_delta, ...@@ -100,24 +204,43 @@ Font PlatformFontMac::DeriveFont(int size_delta,
Font::Weight weight) const { Font::Weight weight) const {
// For some reason, creating fonts using the NSFontDescriptor API's seem to be // For some reason, creating fonts using the NSFontDescriptor API's seem to be
// unreliable. Hence use the NSFontManager. // unreliable. Hence use the NSFontManager.
NSFont* derived_font = native_font_; NSFont* derived = native_font_;
NSFontManager* font_manager = [NSFontManager sharedFontManager]; NSFontManager* font_manager = [NSFontManager sharedFontManager];
NSFontTraitMask bold_trait_mask = if (weight != font_weight_) {
weight >= Font::Weight::BOLD ? NSBoldFontMask : NSUnboldFontMask; // Find a font without any bold traits. Ideally, all bold traits are
derived_font = // removed here, but non-symbolic traits are read-only properties of a
[font_manager convertFont:derived_font toHaveTrait:bold_trait_mask]; // 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];
}
if (style != font_style_) {
NSFontTraitMask italic_trait_mask = NSFontTraitMask italic_trait_mask =
(style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask; (style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask;
derived_font = derived = [font_manager convertFont:derived toHaveTrait:italic_trait_mask];
[font_manager convertFont:derived_font toHaveTrait:italic_trait_mask]; }
derived_font = if (size_delta != 0)
[font_manager convertFont:derived_font toSize:font_size_ + size_delta]; derived = [font_manager convertFont:derived toSize:font_size_ + size_delta];
return Font(new PlatformFontMac(derived_font, font_name_, return Font(new PlatformFontMac(derived, font_name_, font_size_ + size_delta,
font_size_ + size_delta, style, weight)); style, weight));
} }
int PlatformFontMac::GetHeight() { int PlatformFontMac::GetHeight() {
......
...@@ -2,13 +2,19 @@ ...@@ -2,13 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ui/gfx/platform_font_mac.h"
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <stddef.h> #include <stddef.h>
#include "base/mac/mac_util.h"
#include "base/macros.h" #include "base/macros.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 {
TEST(PlatformFontMacTest, DeriveFont) { TEST(PlatformFontMacTest, DeriveFont) {
// Use a base font that support all traits. // Use a base font that support all traits.
gfx::Font base_font("Helvetica", 13); gfx::Font base_font("Helvetica", 13);
...@@ -60,28 +66,202 @@ TEST(PlatformFontMacTest, DeriveFontUnderline) { ...@@ -60,28 +66,202 @@ TEST(PlatformFontMacTest, DeriveFontUnderline) {
EXPECT_EQ(derived_font.GetWeight(), actual_weight); EXPECT_EQ(derived_font.GetWeight(), actual_weight);
} }
// Tests internal methods for extracting gfx::Font properties from the
// underlying CTFont representation.
TEST(PlatformFontMacTest, ConstructFromNativeFont) { TEST(PlatformFontMacTest, ConstructFromNativeFont) {
gfx::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(gfx::Font::NORMAL, normal_font.GetStyle()); EXPECT_EQ(Font::NORMAL, normal_font.GetStyle());
EXPECT_EQ(Font::Weight::NORMAL, normal_font.GetWeight());
gfx::Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]); Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]);
EXPECT_EQ(14, bold_font.GetFontSize()); EXPECT_EQ(14, bold_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_font.GetFontName()); EXPECT_EQ("Helvetica", bold_font.GetFontName());
EXPECT_EQ(gfx::Font::Weight::BOLD, bold_font.GetWeight()); EXPECT_EQ(Font::NORMAL, bold_font.GetStyle());
EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight());
gfx::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(gfx::Font::ITALIC, italic_font.GetStyle()); EXPECT_EQ(Font::ITALIC, italic_font.GetStyle());
EXPECT_EQ(Font::Weight::NORMAL, italic_font.GetWeight());
gfx::Font bold_italic_font( Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]);
[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(gfx::Font::ITALIC, bold_italic_font.GetStyle()); EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle());
EXPECT_EQ(gfx::Font::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.11+.
if (base::mac::IsAtLeastOS10_11()) {
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_9()) {
// On 10.9 the system font doesn't provide finer-grained weights. It's
// either bold or it isn't.
for (int row = 6; row <= 14; ++row) {
SCOPED_TRACE(testing::Message() << "Row: " << row);
ns_font = [manager convertWeight:up ofFont:ns_font];
EXPECT_EQ(Font::Weight::BOLD, 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 - 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.
// 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;
Font base([NSFont systemFontOfSize:13]);
// The resulting, actual font weight after deriving |weight| from |base|.
auto DerivedWeight = [&](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(weight, derived.GetWeight());
// Return the weight enum 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 Font(derived.GetNativeFont()).GetWeight();
};
// Only use NORMAL or BOLD as a base font. Mac font APIs go whacky otherwise.
// See comments in PlatformFontMac::DeriveFont().
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(base_weight, base.GetWeight());
}
// San Francisco doesn't offer anything between THIN and LIGHT.
EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::EXTRA_LIGHT));
// All the rest should map correctly.
EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::THIN));
EXPECT_EQ(Weight::LIGHT, DerivedWeight(Weight::LIGHT));
EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::NORMAL));
EXPECT_EQ(Weight::MEDIUM, DerivedWeight(Weight::MEDIUM));
EXPECT_EQ(Weight::SEMIBOLD, DerivedWeight(Weight::SEMIBOLD));
EXPECT_EQ(Weight::BOLD, DerivedWeight(Weight::BOLD));
EXPECT_EQ(Weight::EXTRA_BOLD, DerivedWeight(Weight::EXTRA_BOLD));
EXPECT_EQ(Weight::BLACK, DerivedWeight(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
...@@ -126,3 +306,5 @@ TEST(PlatformFontMacTest, ValidateFontHeight) { ...@@ -126,3 +306,5 @@ TEST(PlatformFontMacTest, ValidateFontHeight) {
} }
} }
} }
} // namespace gfx
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
namespace views { namespace views {
namespace examples { namespace examples {
ExampleComboboxModel::ExampleComboboxModel(const char** strings, int count) ExampleComboboxModel::ExampleComboboxModel(const char* const* strings,
: strings_(strings), count_(count) { int count)
} : strings_(strings), count_(count) {}
ExampleComboboxModel::~ExampleComboboxModel() { ExampleComboboxModel::~ExampleComboboxModel() {
} }
......
...@@ -13,7 +13,7 @@ namespace examples { ...@@ -13,7 +13,7 @@ namespace examples {
class ExampleComboboxModel : public ui::ComboboxModel { class ExampleComboboxModel : public ui::ComboboxModel {
public: public:
ExampleComboboxModel(const char** strings, int count); ExampleComboboxModel(const char* const* strings, int count);
~ExampleComboboxModel() override; ~ExampleComboboxModel() override;
// ui::ComboboxModel: // ui::ComboboxModel:
...@@ -21,8 +21,8 @@ class ExampleComboboxModel : public ui::ComboboxModel { ...@@ -21,8 +21,8 @@ class ExampleComboboxModel : public ui::ComboboxModel {
base::string16 GetItemAt(int index) override; base::string16 GetItemAt(int index) override;
private: private:
const char** strings_; const char* const* const strings_;
int count_; const int count_;
DISALLOW_COPY_AND_ASSIGN(ExampleComboboxModel); DISALLOW_COPY_AND_ASSIGN(ExampleComboboxModel);
}; };
......
...@@ -50,6 +50,17 @@ const char* kTextExamples[] = { "Short", "Long", "Ampersands", "RTL Hebrew", }; ...@@ -50,6 +50,17 @@ const char* kTextExamples[] = { "Short", "Long", "Ampersands", "RTL Hebrew", };
const char* kElideBehaviors[] = { "Elide", "No Elide", "Fade", }; const char* kElideBehaviors[] = { "Elide", "No Elide", "Fade", };
const char* kPrefixOptions[] = { "Default", "Show", "Hide", }; const char* kPrefixOptions[] = { "Default", "Show", "Hide", };
const char* kHorizontalAligments[] = { "Default", "Left", "Center", "Right", }; const char* kHorizontalAligments[] = { "Default", "Left", "Center", "Right", };
constexpr const char* kWeightLabels[] = {
"Thin", "Extra Light", "Light", "Normal", "Medium",
"Semibold", "Bold", "Extra Bold", "Black",
};
constexpr gfx::Font::Weight kFontWeights[]{
gfx::Font::Weight::THIN, gfx::Font::Weight::EXTRA_LIGHT,
gfx::Font::Weight::LIGHT, gfx::Font::Weight::NORMAL,
gfx::Font::Weight::MEDIUM, gfx::Font::Weight::SEMIBOLD,
gfx::Font::Weight::BOLD, gfx::Font::Weight::EXTRA_BOLD,
gfx::Font::Weight::BLACK,
};
// Toggles bit |flag| on |flags| based on state of |checkbox|. // Toggles bit |flag| on |flags| based on state of |checkbox|.
void SetFlagFromCheckbox(Checkbox* checkbox, int* flags, int flag) { void SetFlagFromCheckbox(Checkbox* checkbox, int* flags, int flag) {
...@@ -87,17 +98,24 @@ class TextExample::TextExampleView : public View { ...@@ -87,17 +98,24 @@ class TextExample::TextExampleView : public View {
void set_elide(gfx::ElideBehavior elide) { elide_ = elide; } void set_elide(gfx::ElideBehavior elide) { elide_ = elide; }
int GetStyle() const { return font_list_.GetFontStyle(); } int GetStyle() const { return font_list_.GetFontStyle(); }
void SetStyle(int style) { font_list_ = font_list_.DeriveWithStyle(style); } void SetStyle(int style) {
base_font_ = base_font_.DeriveWithStyle(style);
font_list_ = font_list_.DeriveWithStyle(style);
}
gfx::Font::Weight GetWeight() const { return font_list_.GetFontWeight(); } gfx::Font::Weight GetWeight() const { return font_list_.GetFontWeight(); }
void SetWeight(gfx::Font::Weight weight) { void SetWeight(gfx::Font::Weight weight) {
font_list_ = font_list_.DeriveWithWeight(weight); font_list_ = base_font_.DeriveWithWeight(weight);
} }
private: private:
// The font used for drawing the text. // The font used for drawing the text.
gfx::FontList font_list_; gfx::FontList font_list_;
// The font without any bold attributes. Mac font APIs struggle to derive UI
// fonts from a base font that isn't NORMAL or BOLD.
gfx::FontList base_font_;
// The text to draw. // The text to draw.
base::string16 text_; base::string16 text_;
...@@ -126,7 +144,7 @@ Checkbox* TextExample::AddCheckbox(GridLayout* layout, const char* name) { ...@@ -126,7 +144,7 @@ Checkbox* TextExample::AddCheckbox(GridLayout* layout, const char* name) {
Combobox* TextExample::AddCombobox(GridLayout* layout, Combobox* TextExample::AddCombobox(GridLayout* layout,
const char* name, const char* name,
const char** strings, const char* const* strings,
int count) { int count) {
layout->StartRow(0, 0); layout->StartRow(0, 0);
layout->AddView(new Label(base::ASCIIToUTF16(name))); layout->AddView(new Label(base::ASCIIToUTF16(name)));
...@@ -163,11 +181,13 @@ void TextExample::CreateExampleView(View* container) { ...@@ -163,11 +181,13 @@ void TextExample::CreateExampleView(View* container) {
arraysize(kPrefixOptions)); arraysize(kPrefixOptions));
text_cb_ = AddCombobox(layout, "Example Text", kTextExamples, text_cb_ = AddCombobox(layout, "Example Text", kTextExamples,
arraysize(kTextExamples)); arraysize(kTextExamples));
weight_cb_ = AddCombobox(layout, "Font Weight", kWeightLabels,
arraysize(kWeightLabels));
weight_cb_->SelectValue(base::ASCIIToUTF16("Normal"));
layout->StartRow(0, 0); layout->StartRow(0, 0);
multiline_checkbox_ = AddCheckbox(layout, "Multiline"); multiline_checkbox_ = AddCheckbox(layout, "Multiline");
break_checkbox_ = AddCheckbox(layout, "Character Break"); break_checkbox_ = AddCheckbox(layout, "Character Break");
bold_checkbox_ = AddCheckbox(layout, "Bold");
italic_checkbox_ = AddCheckbox(layout, "Italic"); italic_checkbox_ = AddCheckbox(layout, "Italic");
underline_checkbox_ = AddCheckbox(layout, "Underline"); underline_checkbox_ = AddCheckbox(layout, "Underline");
...@@ -191,8 +211,6 @@ void TextExample::ButtonPressed(Button* button, const ui::Event& event) { ...@@ -191,8 +211,6 @@ void TextExample::ButtonPressed(Button* button, const ui::Event& event) {
SetFlagFromCheckbox(underline_checkbox_, &style, gfx::Font::UNDERLINE); SetFlagFromCheckbox(underline_checkbox_, &style, gfx::Font::UNDERLINE);
text_view_->set_flags(flags); text_view_->set_flags(flags);
text_view_->SetStyle(style); text_view_->SetStyle(style);
text_view_->SetWeight(bold_checkbox_->checked() ? gfx::Font::Weight::BOLD
: gfx::Font::Weight::NORMAL);
text_view_->SchedulePaint(); text_view_->SchedulePaint();
} }
...@@ -254,6 +272,8 @@ void TextExample::OnPerformAction(Combobox* combobox) { ...@@ -254,6 +272,8 @@ void TextExample::OnPerformAction(Combobox* combobox) {
flags |= gfx::Canvas::HIDE_PREFIX; flags |= gfx::Canvas::HIDE_PREFIX;
break; break;
} }
} else if (combobox == weight_cb_) {
text_view_->SetWeight(kFontWeights[combobox->selected_index()]);
} }
text_view_->set_flags(flags); text_view_->set_flags(flags);
text_view_->SchedulePaint(); text_view_->SchedulePaint();
......
...@@ -38,7 +38,7 @@ class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase, ...@@ -38,7 +38,7 @@ class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
// Creates and adds a combobox to the layout. // Creates and adds a combobox to the layout.
Combobox* AddCombobox(GridLayout* layout, Combobox* AddCombobox(GridLayout* layout,
const char* name, const char* name,
const char** strings, const char* const* strings,
int count); int count);
// ButtonListener: // ButtonListener:
...@@ -63,15 +63,15 @@ class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase, ...@@ -63,15 +63,15 @@ class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
// Combo box to choose one of the sample texts. // Combo box to choose one of the sample texts.
Combobox* text_cb_; Combobox* text_cb_;
// Combo box to choose a font weight.
Combobox* weight_cb_;
// Check box to enable/disable multiline text drawing. // Check box to enable/disable multiline text drawing.
Checkbox* multiline_checkbox_; Checkbox* multiline_checkbox_;
// Check box to enable/disable character break behavior. // Check box to enable/disable character break behavior.
Checkbox* break_checkbox_; Checkbox* break_checkbox_;
// Check box to enable/disable bold style.
Checkbox* bold_checkbox_;
// Check box to enable/disable italic style. // Check box to enable/disable italic style.
Checkbox* italic_checkbox_; Checkbox* italic_checkbox_;
......
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