More text features added.
This commit is contained in:
parent
2bb9896df9
commit
2a7a3ce552
|
@ -36,3 +36,8 @@ pnum
|
|||
tnum
|
||||
frac
|
||||
afrc
|
||||
swsh
|
||||
cswh
|
||||
ornm
|
||||
nalt
|
||||
hist
|
||||
|
|
276
src/core/text.rs
276
src/core/text.rs
|
@ -7,7 +7,7 @@ use crate::core::types::{FontInstanceKey, FontName, FontProperties, FontStyle};
|
|||
use crate::core::var::ContextVar;
|
||||
use crate::properties::text_theme::FontFamilyVar;
|
||||
use fnv::FnvHashMap;
|
||||
use std::{borrow::Cow, fmt, rc::Rc};
|
||||
use std::{borrow::Cow, fmt, mem, rc::Rc};
|
||||
use std::{collections::hash_map::Entry as HEntry, num::NonZeroU32};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use webrender::api::units::Au;
|
||||
|
@ -700,15 +700,6 @@ impl FontFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
/// The most common ligatures, like for `fi`, `ffi`, `th` or similar.
|
||||
///
|
||||
/// This corresponds to OpenType `liga` and `clig` features.
|
||||
///
|
||||
/// `Auto` always activates these ligatures.
|
||||
pub fn common_lig(&mut self) -> FontFeatureSet {
|
||||
self.feature_set([b"liga", b"clig"])
|
||||
}
|
||||
|
||||
/// Font capital glyph variants.
|
||||
///
|
||||
/// See [`CapsVariant`] for more details.
|
||||
|
@ -736,9 +727,18 @@ impl FontFeatures {
|
|||
/// Font numeric spacing variants.
|
||||
///
|
||||
/// See [`NumSpacing`] for more details.
|
||||
#[inline]
|
||||
pub fn num_fraction(&mut self) -> NumFractionFeatures {
|
||||
NumFractionFeatures { features: &mut self.0 }
|
||||
}
|
||||
|
||||
/// Enables stylistic alternatives for sets of character
|
||||
///
|
||||
/// See [`StyleSet`] for more details.
|
||||
#[inline]
|
||||
pub fn style_set(&mut self) -> StyleSetFeatures {
|
||||
StyleSetFeatures { features: &mut self.0 }
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for FontFeatures {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -778,16 +778,6 @@ impl FontFeaturesBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// The most common ligatures, like for `fi`, `ffi`, `th` or similar.
|
||||
///
|
||||
/// This corresponds to OpenType `liga` and `clig` features.
|
||||
///
|
||||
/// `Auto` always activates these ligatures.
|
||||
pub fn common_lig(mut self, state: impl Into<FontFeatureState>) -> Self {
|
||||
self.0.common_lig().set(state);
|
||||
self
|
||||
}
|
||||
|
||||
/// Font capital glyph variants.
|
||||
///
|
||||
/// See [`CapsVariant`] for more details.
|
||||
|
@ -823,6 +813,15 @@ impl FontFeaturesBuilder {
|
|||
self.0.num_fraction().set(state);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables stylistic alternatives for sets of character
|
||||
///
|
||||
/// See [`StyleSet`] for more details.
|
||||
#[inline]
|
||||
pub fn style_set(mut self, state: impl Into<StyleSet>) -> Self {
|
||||
self.0.style_set().set(state);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate `FontFeature` methods in `FontFeatures` and builder methods in `FontFeaturesBuilder`
|
||||
|
@ -830,25 +829,44 @@ impl FontFeaturesBuilder {
|
|||
macro_rules! font_features {
|
||||
($(
|
||||
$(#[$docs:meta])*
|
||||
fn $name:ident($o_name:tt);
|
||||
fn $name:ident($feat0:tt $(, $feat1:tt)?);
|
||||
)+) => {
|
||||
impl FontFeatures {$(
|
||||
$(
|
||||
font_features!{feature $(#[$docs])* fn $name($feat0 $(, $feat1)?); }
|
||||
font_features!{builder $(#[$docs])* fn $name(); }
|
||||
)+
|
||||
};
|
||||
|
||||
(feature $(#[$docs:meta])* fn $name:ident($feat0:tt, $feat1:tt); ) => {
|
||||
impl FontFeatures {
|
||||
$(#[$docs])*
|
||||
#[inline]
|
||||
pub fn $name(&mut self) -> FontFeatureSet {
|
||||
self.feature_set([$feat0, $feat1])
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(feature $(#[$docs:meta])* fn $name:ident($feat0:tt);) => {
|
||||
impl FontFeatures {
|
||||
$(#[$docs])*
|
||||
#[inline]
|
||||
pub fn $name(&mut self) -> FontFeature {
|
||||
self.feature($o_name)
|
||||
self.feature($feat0)
|
||||
}
|
||||
)+}
|
||||
}
|
||||
};
|
||||
|
||||
impl FontFeaturesBuilder {$(
|
||||
(builder $(#[$docs:meta])* fn $name:ident();) => {
|
||||
impl FontFeaturesBuilder {
|
||||
$(#[$docs])*
|
||||
#[inline]
|
||||
pub fn $name(mut self, state: impl Into<FontFeatureState>) -> Self {
|
||||
self.0.$name().set(state);
|
||||
self
|
||||
}
|
||||
)+}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
font_features! {
|
||||
|
@ -859,6 +877,13 @@ font_features! {
|
|||
/// `Auto` always activates these kerning.
|
||||
fn kerning(b"kern");
|
||||
|
||||
/// The most common ligatures, like for `fi`, `ffi`, `th` or similar.
|
||||
///
|
||||
/// This corresponds to OpenType `liga` and `clig` features.
|
||||
///
|
||||
/// `Auto` always activates these ligatures.
|
||||
fn common_lig(b"liga", b"clig");
|
||||
|
||||
/// Ligatures specific to the font, usually decorative.
|
||||
///
|
||||
/// This corresponds to OpenType `dlig` feature.
|
||||
|
@ -893,6 +918,49 @@ font_features! {
|
|||
///
|
||||
/// `Auto` deactivates this feature.
|
||||
fn slashed_zero(b"zero");
|
||||
|
||||
/// Use swashes flourish style.
|
||||
///
|
||||
/// Fonts can have alternative swash styles, you can select then by enabling a number.
|
||||
///
|
||||
/// This corresponds to OpenType `swsh` and `cswh` feature.
|
||||
///
|
||||
/// `Auto` does not use swashes.
|
||||
fn swash(b"swsh", b"cswh");
|
||||
|
||||
/// Use stylistic alternatives.
|
||||
///
|
||||
/// Fonts can have multiple alternative styles, you can select then by enabling a number.
|
||||
///
|
||||
/// This corresponds to OpenType `salt` feature.
|
||||
///
|
||||
/// `Auto` does not use alternative styles.
|
||||
fn stylistic(b"salt");
|
||||
|
||||
/// Use glyphs that were common in the past but not today.
|
||||
///
|
||||
/// This corresponds to OpenType `hist` feature.
|
||||
///
|
||||
/// `Auto` does not use alternative styles.
|
||||
fn historical_forms(b"hist");
|
||||
|
||||
/// Replace letter with fleurons, dingbats and border elements.
|
||||
///
|
||||
/// Fonts can have multiple alternative styles, you can select then by enabling a number.
|
||||
///
|
||||
/// This corresponds to OpenType `ornm` feature.
|
||||
///
|
||||
/// `Auto` does not enable this by default, but some fonts are purely dingbats glyphs.
|
||||
fn ornaments(b"ornm");
|
||||
|
||||
/// Enables annotation alternatives, like circled digits or inverted characters.
|
||||
///
|
||||
/// Fonts can have multiple alternative styles, you can select then by enabling a number.
|
||||
///
|
||||
/// This corresponds to OpenType `nalt` feature.
|
||||
///
|
||||
/// `Auto` does not use alternative styles.
|
||||
fn annotation(b"nalt");
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
@ -1393,6 +1461,55 @@ impl<'a> fmt::Debug for NumFractionFeatures<'a> {
|
|||
fmt::Debug::fmt(&self.state(), f)
|
||||
}
|
||||
}
|
||||
/// Represents the [style_set](FontFeatures::style_set) features. At any time only one of
|
||||
/// these features are be enabled.
|
||||
pub struct StyleSetFeatures<'a> {
|
||||
features: &'a mut FnvHashMap<FontFeatureName, u32>,
|
||||
}
|
||||
impl<'a> StyleSetFeatures<'a> {
|
||||
/// Gets the OpenType names of all the features affected.
|
||||
#[inline]
|
||||
pub fn names(&self) -> [FontFeatureName; 20] {
|
||||
StyleSet::NAMES
|
||||
}
|
||||
|
||||
/// Gets the current state of the features.
|
||||
#[inline]
|
||||
pub fn state(&self) -> StyleSet {
|
||||
for (i, name) in self.names().iter().enumerate() {
|
||||
if self.features.get(name) == Some(&FEATURE_ENABLED) {
|
||||
return (i as u8 + 1).into();
|
||||
}
|
||||
}
|
||||
StyleSet::Auto
|
||||
}
|
||||
fn take_state(&mut self) -> StyleSet {
|
||||
let mut state = StyleSet::Auto;
|
||||
for (i, name) in self.names().iter().enumerate() {
|
||||
if self.features.get(name) == Some(&FEATURE_ENABLED) {
|
||||
state = (i as u8 + 1).into()
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
/// Sets the features.
|
||||
///
|
||||
/// Returns the previous state.
|
||||
#[inline]
|
||||
pub fn set(&mut self, state: impl Into<StyleSet>) -> StyleSet {
|
||||
let prev = self.take_state();
|
||||
if let Some(name) = state.into().name() {
|
||||
self.features.insert(name, FEATURE_ENABLED);
|
||||
}
|
||||
prev
|
||||
}
|
||||
}
|
||||
impl<'a> fmt::Debug for StyleSetFeatures<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.state(), f)
|
||||
}
|
||||
}
|
||||
|
||||
/// State of a [font feature](FontFeatures).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -1571,3 +1688,108 @@ pub enum NumFraction {
|
|||
/// This corresponds to OpenType `afrc` feature.
|
||||
Stacked,
|
||||
}
|
||||
|
||||
/// All possible [style_set](FontFeatures::style_set) features.
|
||||
///
|
||||
/// The styles depend on the font, it is recommended you create an `enum` with named sets that
|
||||
/// converts into this one for each font you wish to use.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum StyleSet {
|
||||
/// Don't use alternative style set.
|
||||
Auto = 0,
|
||||
|
||||
S01,
|
||||
S02,
|
||||
S03,
|
||||
S04,
|
||||
S05,
|
||||
S06,
|
||||
S07,
|
||||
S08,
|
||||
S09,
|
||||
S10,
|
||||
|
||||
S11,
|
||||
S12,
|
||||
S13,
|
||||
S14,
|
||||
S15,
|
||||
S16,
|
||||
S17,
|
||||
S18,
|
||||
S19,
|
||||
S20,
|
||||
}
|
||||
impl_from_and_into_var! {
|
||||
/// `set == 0 || set > 20` is Auto, `set >= 1 && set <= 20` maps to their variant.
|
||||
fn from(set: u8) -> StyleSet {
|
||||
if set > 20 {
|
||||
StyleSet::Auto
|
||||
} else {
|
||||
// SAFETY: We eliminated the bad values in the `if`.
|
||||
unsafe { mem::transmute(set) }
|
||||
}
|
||||
}
|
||||
}
|
||||
impl StyleSet {
|
||||
pub fn name(self) -> Option<FontFeatureName> {
|
||||
if self == StyleSet::Auto {
|
||||
None
|
||||
} else {
|
||||
Some(Self::NAMES[self as usize - 1])
|
||||
}
|
||||
}
|
||||
|
||||
const NAMES: [FontFeatureName; 20] = [
|
||||
b"ss01", b"ss02", b"ss03", b"ss04", b"ss05", b"ss06", b"ss07", b"ss08", b"ss09", b"ss10", b"ss11", b"ss12", b"ss13", b"ss14",
|
||||
b"ss15", b"ss16", b"ss17", b"ss18", b"ss19", b"ss20",
|
||||
];
|
||||
}
|
||||
|
||||
/// All possible [character_variant](FontFeatures::character_variant) features (`cv00..=cv99`).
|
||||
///
|
||||
/// The styles depend on the font, it is recommended you create `const`s with named variants to use with a specific font.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct CharacterVariant(u8);
|
||||
impl CharacterVariant {
|
||||
/// New variant.
|
||||
///
|
||||
/// Returns auto if `v == 0 || v > 99`.
|
||||
#[inline]
|
||||
pub const fn new(v: u8) -> Self {
|
||||
if v > 99 {
|
||||
CharacterVariant(0)
|
||||
} else {
|
||||
CharacterVariant(v)
|
||||
}
|
||||
}
|
||||
|
||||
/// New auto.
|
||||
#[inline]
|
||||
pub const fn auto() -> Self {
|
||||
CharacterVariant(0)
|
||||
}
|
||||
|
||||
/// Is auto.
|
||||
#[inline]
|
||||
pub const fn is_auto(self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
|
||||
/// Gets the feature name if it is not auto.
|
||||
#[inline]
|
||||
pub fn name(self) -> Option<FontFeatureName> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Gets the variant number, if it is not auto.
|
||||
#[inline]
|
||||
pub const fn variant(self) -> Option<u8> {
|
||||
if self.0 == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,3 +264,39 @@ pub fn font_num_spacing(child: impl UiNode, state: impl IntoVar<NumSpacing>) ->
|
|||
pub fn font_num_fraction(child: impl UiNode, state: impl IntoVar<NumFraction>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.num_fraction().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font swash features.
|
||||
#[property(context)]
|
||||
pub fn font_swash(child: impl UiNode, state: impl IntoVar<FontFeatureState>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.swash().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font stylistic alternative feature.
|
||||
#[property(context)]
|
||||
pub fn font_stylistic(child: impl UiNode, state: impl IntoVar<FontFeatureState>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.stylistic().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font historical forms alternative feature.
|
||||
#[property(context)]
|
||||
pub fn font_historical_forms(child: impl UiNode, state: impl IntoVar<FontFeatureState>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.historical_forms().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font ornaments alternative feature.
|
||||
#[property(context)]
|
||||
pub fn font_ornaments(child: impl UiNode, state: impl IntoVar<FontFeatureState>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.ornaments().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font annotation alternative feature.
|
||||
#[property(context)]
|
||||
pub fn font_annotation(child: impl UiNode, state: impl IntoVar<FontFeatureState>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.annotation().set(s))
|
||||
}
|
||||
|
||||
/// Sets the font stylistic set alternative feature.
|
||||
#[property(context)]
|
||||
pub fn font_style_set(child: impl UiNode, state: impl IntoVar<StyleSet>) -> impl UiNode {
|
||||
with_font_feature(child, state, |f, s| f.style_set().set(s))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue