Honor more OpenType features
This commit is contained in:
parent
9181ac9872
commit
f9d793cb4a
4 changed files with 500 additions and 134 deletions
|
@ -24,6 +24,39 @@ pub type GlyphId = u32;
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct Features {
|
pub struct Features {
|
||||||
pub calt: Option<bool>,
|
pub calt: Option<bool>,
|
||||||
|
pub case: Option<bool>,
|
||||||
|
pub cpsp: Option<bool>,
|
||||||
|
pub frac: Option<bool>,
|
||||||
|
pub liga: Option<bool>,
|
||||||
|
pub onum: Option<bool>,
|
||||||
|
pub ordn: Option<bool>,
|
||||||
|
pub pnum: Option<bool>,
|
||||||
|
pub ss01: Option<bool>,
|
||||||
|
pub ss02: Option<bool>,
|
||||||
|
pub ss03: Option<bool>,
|
||||||
|
pub ss04: Option<bool>,
|
||||||
|
pub ss05: Option<bool>,
|
||||||
|
pub ss06: Option<bool>,
|
||||||
|
pub ss07: Option<bool>,
|
||||||
|
pub ss08: Option<bool>,
|
||||||
|
pub ss09: Option<bool>,
|
||||||
|
pub ss10: Option<bool>,
|
||||||
|
pub ss11: Option<bool>,
|
||||||
|
pub ss12: Option<bool>,
|
||||||
|
pub ss13: Option<bool>,
|
||||||
|
pub ss14: Option<bool>,
|
||||||
|
pub ss15: Option<bool>,
|
||||||
|
pub ss16: Option<bool>,
|
||||||
|
pub ss17: Option<bool>,
|
||||||
|
pub ss18: Option<bool>,
|
||||||
|
pub ss19: Option<bool>,
|
||||||
|
pub ss20: Option<bool>,
|
||||||
|
pub subs: Option<bool>,
|
||||||
|
pub sups: Option<bool>,
|
||||||
|
pub swsh: Option<bool>,
|
||||||
|
pub titl: Option<bool>,
|
||||||
|
pub tnum: Option<bool>,
|
||||||
|
pub zero: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -16,29 +16,19 @@ use core_foundation::{
|
||||||
array::CFIndex,
|
array::CFIndex,
|
||||||
attributed_string::{CFAttributedStringRef, CFMutableAttributedString},
|
attributed_string::{CFAttributedStringRef, CFMutableAttributedString},
|
||||||
base::{CFRange, TCFType},
|
base::{CFRange, TCFType},
|
||||||
number::CFNumber,
|
|
||||||
string::CFString,
|
string::CFString,
|
||||||
};
|
};
|
||||||
use core_graphics::{
|
use core_graphics::{
|
||||||
base::{kCGImageAlphaPremultipliedLast, CGGlyph},
|
base::{kCGImageAlphaPremultipliedLast, CGGlyph},
|
||||||
color_space::CGColorSpace,
|
color_space::CGColorSpace,
|
||||||
context::CGContext,
|
context::CGContext,
|
||||||
geometry::CGAffineTransform,
|
|
||||||
};
|
|
||||||
use core_text::{
|
|
||||||
font::{CTFont, CTFontRef},
|
|
||||||
font_descriptor::{
|
|
||||||
CTFontDescriptor, CTFontDescriptorCreateCopyWithFeature, CTFontDescriptorRef,
|
|
||||||
},
|
|
||||||
line::CTLine,
|
|
||||||
string_attributes::kCTFontAttributeName,
|
|
||||||
};
|
};
|
||||||
|
use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName};
|
||||||
use font_kit::{
|
use font_kit::{
|
||||||
font::Font, handle::Handle, hinting::HintingOptions, source::SystemSource,
|
handle::Handle, hinting::HintingOptions, source::SystemSource, sources::mem::MemSource,
|
||||||
sources::mem::MemSource,
|
|
||||||
};
|
};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, ptr, sync::Arc};
|
use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, sync::Arc};
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
const kCGImageAlphaOnly: u32 = 7;
|
const kCGImageAlphaOnly: u32 = 7;
|
||||||
|
@ -147,16 +137,7 @@ impl FontSystemState {
|
||||||
.or_else(|_| self.system_source.select_family_by_name(name))?;
|
.or_else(|_| self.system_source.select_family_by_name(name))?;
|
||||||
for font in family.fonts() {
|
for font in family.fonts() {
|
||||||
let mut font = font.load()?;
|
let mut font = font.load()?;
|
||||||
|
open_type::apply_features(&mut font, features);
|
||||||
if let Some(calt) = features.calt {
|
|
||||||
let value = if calt {
|
|
||||||
open_type::kContextualAlternatesOnSelector
|
|
||||||
} else {
|
|
||||||
open_type::kContextualAlternatesOffSelector
|
|
||||||
};
|
|
||||||
font = toggle_open_type_feature(&font, open_type::kContextualAlternatesType, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let font_id = FontId(self.fonts.len());
|
let font_id = FontId(self.fonts.len());
|
||||||
font_ids.push(font_id);
|
font_ids.push(font_id);
|
||||||
let postscript_name = font.postscript_name().unwrap();
|
let postscript_name = font.postscript_name().unwrap();
|
||||||
|
@ -512,33 +493,6 @@ extern "C" {
|
||||||
start_index: CFIndex,
|
start_index: CFIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> CFIndex;
|
) -> CFIndex;
|
||||||
|
|
||||||
fn CTFontCreateCopyWithAttributes(
|
|
||||||
font: CTFontRef,
|
|
||||||
size: CGFloat,
|
|
||||||
matrix: *const CGAffineTransform,
|
|
||||||
attributes: CTFontDescriptorRef,
|
|
||||||
) -> CTFontRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_open_type_feature(font: &Font, type_identifier: i32, selector_identifier: i32) -> Font {
|
|
||||||
let native_font = font.native_font();
|
|
||||||
unsafe {
|
|
||||||
let new_descriptor = CTFontDescriptorCreateCopyWithFeature(
|
|
||||||
native_font.copy_descriptor().as_concrete_TypeRef(),
|
|
||||||
CFNumber::from(type_identifier).as_concrete_TypeRef(),
|
|
||||||
CFNumber::from(selector_identifier).as_concrete_TypeRef(),
|
|
||||||
);
|
|
||||||
let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor);
|
|
||||||
let new_font = CTFontCreateCopyWithAttributes(
|
|
||||||
font.native_font().as_concrete_TypeRef(),
|
|
||||||
0.0,
|
|
||||||
ptr::null(),
|
|
||||||
new_descriptor.as_concrete_TypeRef(),
|
|
||||||
);
|
|
||||||
let new_font = CTFont::wrap_under_create_rule(new_font);
|
|
||||||
Font::from_native_font(new_font)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,83 +1,395 @@
|
||||||
#![allow(unused, non_upper_case_globals)]
|
#![allow(unused, non_upper_case_globals)]
|
||||||
|
|
||||||
pub const kAltHalfWidthTextSelector: i32 = 6;
|
use std::ptr;
|
||||||
pub const kAltProportionalTextSelector: i32 = 5;
|
|
||||||
pub const kAlternateHorizKanaOffSelector: i32 = 1;
|
use crate::fonts::Features;
|
||||||
pub const kAlternateHorizKanaOnSelector: i32 = 0;
|
use cocoa::appkit::CGFloat;
|
||||||
pub const kAlternateKanaType: i32 = 34;
|
use core_foundation::{base::TCFType, number::CFNumber};
|
||||||
pub const kAlternateVertKanaOffSelector: i32 = 3;
|
use core_graphics::geometry::CGAffineTransform;
|
||||||
pub const kAlternateVertKanaOnSelector: i32 = 2;
|
use core_text::{
|
||||||
pub const kCaseSensitiveLayoutOffSelector: i32 = 1;
|
font::{CTFont, CTFontRef},
|
||||||
pub const kCaseSensitiveLayoutOnSelector: i32 = 0;
|
font_descriptor::{
|
||||||
pub const kCaseSensitiveLayoutType: i32 = 33;
|
CTFontDescriptor, CTFontDescriptorCreateCopyWithFeature, CTFontDescriptorRef,
|
||||||
pub const kCaseSensitiveSpacingOffSelector: i32 = 3;
|
},
|
||||||
pub const kCaseSensitiveSpacingOnSelector: i32 = 2;
|
};
|
||||||
pub const kContextualAlternatesOffSelector: i32 = 1;
|
use font_kit::font::Font;
|
||||||
pub const kContextualAlternatesOnSelector: i32 = 0;
|
|
||||||
pub const kContextualAlternatesType: i32 = 36;
|
const kCaseSensitiveLayoutOffSelector: i32 = 1;
|
||||||
pub const kContextualLigaturesOffSelector: i32 = 19;
|
const kCaseSensitiveLayoutOnSelector: i32 = 0;
|
||||||
pub const kContextualLigaturesOnSelector: i32 = 18;
|
const kCaseSensitiveLayoutType: i32 = 33;
|
||||||
pub const kContextualSwashAlternatesOffSelector: i32 = 5;
|
const kCaseSensitiveSpacingOffSelector: i32 = 3;
|
||||||
pub const kContextualSwashAlternatesOnSelector: i32 = 4;
|
const kCaseSensitiveSpacingOnSelector: i32 = 2;
|
||||||
pub const kDefaultLowerCaseSelector: i32 = 0;
|
const kCharacterAlternativesType: i32 = 17;
|
||||||
pub const kDefaultUpperCaseSelector: i32 = 0;
|
const kCommonLigaturesOffSelector: i32 = 3;
|
||||||
pub const kHistoricalLigaturesOffSelector: i32 = 21;
|
const kCommonLigaturesOnSelector: i32 = 2;
|
||||||
pub const kHistoricalLigaturesOnSelector: i32 = 20;
|
const kContextualAlternatesOffSelector: i32 = 1;
|
||||||
pub const kHojoCharactersSelector: i32 = 12;
|
const kContextualAlternatesOnSelector: i32 = 0;
|
||||||
pub const kJIS2004CharactersSelector: i32 = 11;
|
const kContextualAlternatesType: i32 = 36;
|
||||||
pub const kLowerCasePetiteCapsSelector: i32 = 2;
|
const kContextualLigaturesOffSelector: i32 = 19;
|
||||||
pub const kLowerCaseSmallCapsSelector: i32 = 1;
|
const kContextualLigaturesOnSelector: i32 = 18;
|
||||||
pub const kLowerCaseType: i32 = 37;
|
const kContextualSwashAlternatesOffSelector: i32 = 5;
|
||||||
pub const kMathematicalGreekOffSelector: i32 = 11;
|
const kContextualSwashAlternatesOnSelector: i32 = 4;
|
||||||
pub const kMathematicalGreekOnSelector: i32 = 10;
|
const kDefaultLowerCaseSelector: i32 = 0;
|
||||||
pub const kNLCCharactersSelector: i32 = 13;
|
const kDefaultUpperCaseSelector: i32 = 0;
|
||||||
pub const kQuarterWidthTextSelector: i32 = 4;
|
const kDiagonalFractionsSelector: i32 = 2;
|
||||||
pub const kScientificInferiorsSelector: i32 = 4;
|
const kFractionsType: i32 = 11;
|
||||||
pub const kStylisticAltEightOffSelector: i32 = 17;
|
const kHistoricalLigaturesOffSelector: i32 = 21;
|
||||||
pub const kStylisticAltEightOnSelector: i32 = 16;
|
const kHistoricalLigaturesOnSelector: i32 = 20;
|
||||||
pub const kStylisticAltEighteenOffSelector: i32 = 37;
|
const kHojoCharactersSelector: i32 = 12;
|
||||||
pub const kStylisticAltEighteenOnSelector: i32 = 36;
|
const kInferiorsSelector: i32 = 2;
|
||||||
pub const kStylisticAltElevenOffSelector: i32 = 23;
|
const kJIS2004CharactersSelector: i32 = 11;
|
||||||
pub const kStylisticAltElevenOnSelector: i32 = 22;
|
const kLigaturesType: i32 = 1;
|
||||||
pub const kStylisticAltFifteenOffSelector: i32 = 31;
|
const kLowerCasePetiteCapsSelector: i32 = 2;
|
||||||
pub const kStylisticAltFifteenOnSelector: i32 = 30;
|
const kLowerCaseSmallCapsSelector: i32 = 1;
|
||||||
pub const kStylisticAltFiveOffSelector: i32 = 11;
|
const kLowerCaseType: i32 = 37;
|
||||||
pub const kStylisticAltFiveOnSelector: i32 = 10;
|
const kLowerCaseNumbersSelector: i32 = 0;
|
||||||
pub const kStylisticAltFourOffSelector: i32 = 9;
|
const kMathematicalGreekOffSelector: i32 = 11;
|
||||||
pub const kStylisticAltFourOnSelector: i32 = 8;
|
const kMathematicalGreekOnSelector: i32 = 10;
|
||||||
pub const kStylisticAltFourteenOffSelector: i32 = 29;
|
const kMonospacedNumbersSelector: i32 = 0;
|
||||||
pub const kStylisticAltFourteenOnSelector: i32 = 28;
|
const kNLCCharactersSelector: i32 = 13;
|
||||||
pub const kStylisticAltNineOffSelector: i32 = 19;
|
const kNoFractionsSelector: i32 = 0;
|
||||||
pub const kStylisticAltNineOnSelector: i32 = 18;
|
const kNormalPositionSelector: i32 = 0;
|
||||||
pub const kStylisticAltNineteenOffSelector: i32 = 39;
|
const kNoStyleOptionsSelector: i32 = 0;
|
||||||
pub const kStylisticAltNineteenOnSelector: i32 = 38;
|
const kNumberCaseType: i32 = 21;
|
||||||
pub const kStylisticAltOneOffSelector: i32 = 3;
|
const kNumberSpacingType: i32 = 6;
|
||||||
pub const kStylisticAltOneOnSelector: i32 = 2;
|
const kOrdinalsSelector: i32 = 3;
|
||||||
pub const kStylisticAltSevenOffSelector: i32 = 15;
|
const kProportionalNumbersSelector: i32 = 1;
|
||||||
pub const kStylisticAltSevenOnSelector: i32 = 14;
|
const kQuarterWidthTextSelector: i32 = 4;
|
||||||
pub const kStylisticAltSeventeenOffSelector: i32 = 35;
|
const kScientificInferiorsSelector: i32 = 4;
|
||||||
pub const kStylisticAltSeventeenOnSelector: i32 = 34;
|
const kSlashedZeroOffSelector: i32 = 5;
|
||||||
pub const kStylisticAltSixOffSelector: i32 = 13;
|
const kSlashedZeroOnSelector: i32 = 4;
|
||||||
pub const kStylisticAltSixOnSelector: i32 = 12;
|
const kStyleOptionsType: i32 = 19;
|
||||||
pub const kStylisticAltSixteenOffSelector: i32 = 33;
|
const kStylisticAltEighteenOffSelector: i32 = 37;
|
||||||
pub const kStylisticAltSixteenOnSelector: i32 = 32;
|
const kStylisticAltEighteenOnSelector: i32 = 36;
|
||||||
pub const kStylisticAltTenOffSelector: i32 = 21;
|
const kStylisticAltEightOffSelector: i32 = 17;
|
||||||
pub const kStylisticAltTenOnSelector: i32 = 20;
|
const kStylisticAltEightOnSelector: i32 = 16;
|
||||||
pub const kStylisticAltThirteenOffSelector: i32 = 27;
|
const kStylisticAltElevenOffSelector: i32 = 23;
|
||||||
pub const kStylisticAltThirteenOnSelector: i32 = 26;
|
const kStylisticAltElevenOnSelector: i32 = 22;
|
||||||
pub const kStylisticAltThreeOffSelector: i32 = 7;
|
const kStylisticAlternativesType: i32 = 35;
|
||||||
pub const kStylisticAltThreeOnSelector: i32 = 6;
|
const kStylisticAltFifteenOffSelector: i32 = 31;
|
||||||
pub const kStylisticAltTwelveOffSelector: i32 = 25;
|
const kStylisticAltFifteenOnSelector: i32 = 30;
|
||||||
pub const kStylisticAltTwelveOnSelector: i32 = 24;
|
const kStylisticAltFiveOffSelector: i32 = 11;
|
||||||
pub const kStylisticAltTwentyOffSelector: i32 = 41;
|
const kStylisticAltFiveOnSelector: i32 = 10;
|
||||||
pub const kStylisticAltTwentyOnSelector: i32 = 40;
|
const kStylisticAltFourOffSelector: i32 = 9;
|
||||||
pub const kStylisticAltTwoOffSelector: i32 = 5;
|
const kStylisticAltFourOnSelector: i32 = 8;
|
||||||
pub const kStylisticAltTwoOnSelector: i32 = 4;
|
const kStylisticAltFourteenOffSelector: i32 = 29;
|
||||||
pub const kStylisticAlternativesType: i32 = 35;
|
const kStylisticAltFourteenOnSelector: i32 = 28;
|
||||||
pub const kSwashAlternatesOffSelector: i32 = 3;
|
const kStylisticAltNineOffSelector: i32 = 19;
|
||||||
pub const kSwashAlternatesOnSelector: i32 = 2;
|
const kStylisticAltNineOnSelector: i32 = 18;
|
||||||
pub const kThirdWidthTextSelector: i32 = 3;
|
const kStylisticAltNineteenOffSelector: i32 = 39;
|
||||||
pub const kTraditionalNamesCharactersSelector: i32 = 14;
|
const kStylisticAltNineteenOnSelector: i32 = 38;
|
||||||
pub const kUpperCasePetiteCapsSelector: i32 = 2;
|
const kStylisticAltOneOffSelector: i32 = 3;
|
||||||
pub const kUpperCaseSmallCapsSelector: i32 = 1;
|
const kStylisticAltOneOnSelector: i32 = 2;
|
||||||
pub const kUpperCaseType: i32 = 38;
|
const kStylisticAltSevenOffSelector: i32 = 15;
|
||||||
|
const kStylisticAltSevenOnSelector: i32 = 14;
|
||||||
|
const kStylisticAltSeventeenOffSelector: i32 = 35;
|
||||||
|
const kStylisticAltSeventeenOnSelector: i32 = 34;
|
||||||
|
const kStylisticAltSixOffSelector: i32 = 13;
|
||||||
|
const kStylisticAltSixOnSelector: i32 = 12;
|
||||||
|
const kStylisticAltSixteenOffSelector: i32 = 33;
|
||||||
|
const kStylisticAltSixteenOnSelector: i32 = 32;
|
||||||
|
const kStylisticAltTenOffSelector: i32 = 21;
|
||||||
|
const kStylisticAltTenOnSelector: i32 = 20;
|
||||||
|
const kStylisticAltThirteenOffSelector: i32 = 27;
|
||||||
|
const kStylisticAltThirteenOnSelector: i32 = 26;
|
||||||
|
const kStylisticAltThreeOffSelector: i32 = 7;
|
||||||
|
const kStylisticAltThreeOnSelector: i32 = 6;
|
||||||
|
const kStylisticAltTwelveOffSelector: i32 = 25;
|
||||||
|
const kStylisticAltTwelveOnSelector: i32 = 24;
|
||||||
|
const kStylisticAltTwentyOffSelector: i32 = 41;
|
||||||
|
const kStylisticAltTwentyOnSelector: i32 = 40;
|
||||||
|
const kStylisticAltTwoOffSelector: i32 = 5;
|
||||||
|
const kStylisticAltTwoOnSelector: i32 = 4;
|
||||||
|
const kSuperiorsSelector: i32 = 1;
|
||||||
|
const kSwashAlternatesOffSelector: i32 = 3;
|
||||||
|
const kSwashAlternatesOnSelector: i32 = 2;
|
||||||
|
const kTitlingCapsSelector: i32 = 4;
|
||||||
|
const kTypographicExtrasType: i32 = 14;
|
||||||
|
const kVerticalFractionsSelector: i32 = 1;
|
||||||
|
const kVerticalPositionType: i32 = 10;
|
||||||
|
|
||||||
|
pub fn apply_features(font: &mut Font, features: &Features) {
|
||||||
|
// See https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/third_party/harfbuzz-ng/src/hb-coretext.cc
|
||||||
|
// for a reference implementation.
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.calt,
|
||||||
|
kContextualAlternatesType,
|
||||||
|
kContextualAlternatesOnSelector,
|
||||||
|
kContextualAlternatesOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.case,
|
||||||
|
kCaseSensitiveLayoutType,
|
||||||
|
kCaseSensitiveLayoutOnSelector,
|
||||||
|
kCaseSensitiveLayoutOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.cpsp,
|
||||||
|
kCaseSensitiveLayoutType,
|
||||||
|
kCaseSensitiveSpacingOnSelector,
|
||||||
|
kCaseSensitiveSpacingOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.frac,
|
||||||
|
kFractionsType,
|
||||||
|
kDiagonalFractionsSelector,
|
||||||
|
kNoFractionsSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.liga,
|
||||||
|
kLigaturesType,
|
||||||
|
kCommonLigaturesOnSelector,
|
||||||
|
kCommonLigaturesOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.onum,
|
||||||
|
kNumberCaseType,
|
||||||
|
kLowerCaseNumbersSelector,
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ordn,
|
||||||
|
kVerticalPositionType,
|
||||||
|
kOrdinalsSelector,
|
||||||
|
kNormalPositionSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.pnum,
|
||||||
|
kNumberSpacingType,
|
||||||
|
kProportionalNumbersSelector,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss01,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltOneOnSelector,
|
||||||
|
kStylisticAltOneOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss02,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltTwoOnSelector,
|
||||||
|
kStylisticAltTwoOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss03,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltThreeOnSelector,
|
||||||
|
kStylisticAltThreeOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss04,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltFourOnSelector,
|
||||||
|
kStylisticAltFourOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss05,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltFiveOnSelector,
|
||||||
|
kStylisticAltFiveOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss06,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltSixOnSelector,
|
||||||
|
kStylisticAltSixOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss07,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltSevenOnSelector,
|
||||||
|
kStylisticAltSevenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss08,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltEightOnSelector,
|
||||||
|
kStylisticAltEightOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss09,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltNineOnSelector,
|
||||||
|
kStylisticAltNineOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss10,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltTenOnSelector,
|
||||||
|
kStylisticAltTenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss11,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltElevenOnSelector,
|
||||||
|
kStylisticAltElevenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss12,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltTwelveOnSelector,
|
||||||
|
kStylisticAltTwelveOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss13,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltThirteenOnSelector,
|
||||||
|
kStylisticAltThirteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss14,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltFourteenOnSelector,
|
||||||
|
kStylisticAltFourteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss15,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltFifteenOnSelector,
|
||||||
|
kStylisticAltFifteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss16,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltSixteenOnSelector,
|
||||||
|
kStylisticAltSixteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss17,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltSeventeenOnSelector,
|
||||||
|
kStylisticAltSeventeenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss18,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltEighteenOnSelector,
|
||||||
|
kStylisticAltEighteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss19,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltNineteenOnSelector,
|
||||||
|
kStylisticAltNineteenOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.ss20,
|
||||||
|
kStylisticAlternativesType,
|
||||||
|
kStylisticAltTwentyOnSelector,
|
||||||
|
kStylisticAltTwentyOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.subs,
|
||||||
|
kVerticalPositionType,
|
||||||
|
kInferiorsSelector,
|
||||||
|
kNormalPositionSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.sups,
|
||||||
|
kVerticalPositionType,
|
||||||
|
kSuperiorsSelector,
|
||||||
|
kNormalPositionSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.swsh,
|
||||||
|
kContextualAlternatesType,
|
||||||
|
kSwashAlternatesOnSelector,
|
||||||
|
kSwashAlternatesOffSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.titl,
|
||||||
|
kStyleOptionsType,
|
||||||
|
kTitlingCapsSelector,
|
||||||
|
kNoStyleOptionsSelector,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.tnum,
|
||||||
|
kNumberSpacingType,
|
||||||
|
kMonospacedNumbersSelector,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
toggle_open_type_feature(
|
||||||
|
font,
|
||||||
|
features.zero,
|
||||||
|
kTypographicExtrasType,
|
||||||
|
kSlashedZeroOnSelector,
|
||||||
|
kSlashedZeroOffSelector,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_open_type_feature(
|
||||||
|
font: &mut Font,
|
||||||
|
enabled: Option<bool>,
|
||||||
|
type_identifier: i32,
|
||||||
|
on_selector_identifier: i32,
|
||||||
|
off_selector_identifier: i32,
|
||||||
|
) {
|
||||||
|
if let Some(enabled) = enabled {
|
||||||
|
let native_font = font.native_font();
|
||||||
|
unsafe {
|
||||||
|
let selector_identifier = if enabled {
|
||||||
|
on_selector_identifier
|
||||||
|
} else {
|
||||||
|
off_selector_identifier
|
||||||
|
};
|
||||||
|
let new_descriptor = CTFontDescriptorCreateCopyWithFeature(
|
||||||
|
native_font.copy_descriptor().as_concrete_TypeRef(),
|
||||||
|
CFNumber::from(type_identifier).as_concrete_TypeRef(),
|
||||||
|
CFNumber::from(selector_identifier).as_concrete_TypeRef(),
|
||||||
|
);
|
||||||
|
let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor);
|
||||||
|
let new_font = CTFontCreateCopyWithAttributes(
|
||||||
|
font.native_font().as_concrete_TypeRef(),
|
||||||
|
0.0,
|
||||||
|
ptr::null(),
|
||||||
|
new_descriptor.as_concrete_TypeRef(),
|
||||||
|
);
|
||||||
|
let new_font = CTFont::wrap_under_create_rule(new_font);
|
||||||
|
*font = Font::from_native_font(new_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(name = "CoreText", kind = "framework")]
|
||||||
|
extern "C" {
|
||||||
|
fn CTFontCreateCopyWithAttributes(
|
||||||
|
font: CTFontRef,
|
||||||
|
size: CGFloat,
|
||||||
|
matrix: *const CGAffineTransform,
|
||||||
|
attributes: CTFontDescriptorRef,
|
||||||
|
) -> CTFontRef;
|
||||||
|
}
|
||||||
|
|
|
@ -98,11 +98,78 @@ export interface TextProperties {
|
||||||
weight?: FontWeight
|
weight?: FontWeight
|
||||||
underline?: boolean
|
underline?: boolean
|
||||||
color?: string,
|
color?: string,
|
||||||
features?: TextFeatures,
|
features?: FontFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TextFeatures {
|
interface FontFeatures {
|
||||||
calt?: boolean
|
/** Contextual Alternates: Applies a second substitution feature based on a match of a character pattern within a context of surrounding patterns */
|
||||||
|
calt?: boolean;
|
||||||
|
/** Case-Sensitive Forms: Shifts various punctuation marks up to a position that works better with all-capital sequences */
|
||||||
|
case?: boolean;
|
||||||
|
/** Capital Spacing: Adjusts inter-glyph spacing for all-capital text */
|
||||||
|
cpsp?: boolean;
|
||||||
|
/** Fractions: Replaces figures separated by a slash with diagonal fractions */
|
||||||
|
frac?: boolean;
|
||||||
|
/** Standard Ligatures: Replaces a sequence of glyphs with a single glyph which is preferred for typographic purposes */
|
||||||
|
liga?: boolean;
|
||||||
|
/** Oldstyle Figures: Changes selected figures from the default or lining style to oldstyle form. */
|
||||||
|
onum?: boolean;
|
||||||
|
/** Ordinals: Replaces default alphabetic glyphs with the corresponding ordinal forms for use after figures */
|
||||||
|
ordn?: boolean;
|
||||||
|
/** Proportional Figures: Replaces figure glyphs set on uniform (tabular) widths with corresponding glyphs set on proportional widths */
|
||||||
|
pnum?: boolean;
|
||||||
|
/** Stylistic set 01 */
|
||||||
|
ss01?: boolean;
|
||||||
|
/** Stylistic set 02 */
|
||||||
|
ss02?: boolean;
|
||||||
|
/** Stylistic set 03 */
|
||||||
|
ss03?: boolean;
|
||||||
|
/** Stylistic set 04 */
|
||||||
|
ss04?: boolean;
|
||||||
|
/** Stylistic set 05 */
|
||||||
|
ss05?: boolean;
|
||||||
|
/** Stylistic set 06 */
|
||||||
|
ss06?: boolean;
|
||||||
|
/** Stylistic set 07 */
|
||||||
|
ss07?: boolean;
|
||||||
|
/** Stylistic set 08 */
|
||||||
|
ss08?: boolean;
|
||||||
|
/** Stylistic set 09 */
|
||||||
|
ss09?: boolean;
|
||||||
|
/** Stylistic set 10 */
|
||||||
|
ss10?: boolean;
|
||||||
|
/** Stylistic set 11 */
|
||||||
|
ss11?: boolean;
|
||||||
|
/** Stylistic set 12 */
|
||||||
|
ss12?: boolean;
|
||||||
|
/** Stylistic set 13 */
|
||||||
|
ss13?: boolean;
|
||||||
|
/** Stylistic set 14 */
|
||||||
|
ss14?: boolean;
|
||||||
|
/** Stylistic set 15 */
|
||||||
|
ss15?: boolean;
|
||||||
|
/** Stylistic set 16 */
|
||||||
|
ss16?: boolean;
|
||||||
|
/** Stylistic set 17 */
|
||||||
|
ss17?: boolean;
|
||||||
|
/** Stylistic set 18 */
|
||||||
|
ss18?: boolean;
|
||||||
|
/** Stylistic set 19 */
|
||||||
|
ss19?: boolean;
|
||||||
|
/** Stylistic set 20 */
|
||||||
|
ss20?: boolean;
|
||||||
|
/** Subscript: Replaces default glyphs with subscript glyphs */
|
||||||
|
subs?: boolean;
|
||||||
|
/** Superscript: Replaces default glyphs with superscript glyphs */
|
||||||
|
sups?: boolean;
|
||||||
|
/** Swash: Replaces default glyphs with swash glyphs for stylistic purposes */
|
||||||
|
swsh?: boolean;
|
||||||
|
/** Titling: Replaces default glyphs with titling glyphs for use in large-size settings */
|
||||||
|
titl?: boolean;
|
||||||
|
/** Tabular Figures: Replaces figure glyphs set on proportional widths with corresponding glyphs set on uniform (tabular) widths */
|
||||||
|
tnum?: boolean;
|
||||||
|
/** Slashed Zero: Replaces default zero with a slashed zero for better distinction between "0" and "O" */
|
||||||
|
zero?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function text(
|
export function text(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue