Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion parley/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ mod util;

pub mod editing;
pub mod layout;
pub mod setting;
pub mod style;

#[cfg(test)]
Expand Down
49 changes: 16 additions & 33 deletions parley/src/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub(crate) use range::RangedStyleBuilder;
use alloc::{vec, vec::Vec};

use super::style::{
Brush, FontFamily, FontFamilyName, FontFeature, FontFeatures, FontStyle, FontVariation,
FontVariations, FontWeight, FontWidth, StyleProperty,
Brush, FontFamily, FontFamilyName, FontFeature, FontStyle, FontVariation, FontWeight,
FontWidth, StyleProperty,
};
use crate::font::FontContext;
use crate::style::TextStyle;
Expand Down Expand Up @@ -139,8 +139,12 @@ impl ResolveContext {
StyleProperty::FontWidth(value) => FontWidth(*value),
StyleProperty::FontStyle(value) => FontStyle(*value),
StyleProperty::FontWeight(value) => FontWeight(*value),
StyleProperty::FontVariations(value) => FontVariations(self.resolve_variations(value)),
StyleProperty::FontFeatures(value) => FontFeatures(self.resolve_features(value)),
StyleProperty::FontVariations(value) => {
FontVariations(self.resolve_variations(value.as_ref()))
}
StyleProperty::FontFeatures(value) => {
FontFeatures(self.resolve_features(value.as_ref()))
}
StyleProperty::Locale(value) => Locale(
value.and_then(|v| icu_locale_core::Locale::try_from_str(v).map(|v| v.id).ok()),
),
Expand Down Expand Up @@ -176,8 +180,8 @@ impl ResolveContext {
font_width: raw_style.font_width,
font_style: raw_style.font_style,
font_weight: raw_style.font_weight,
font_variations: self.resolve_variations(&raw_style.font_variations),
font_features: self.resolve_features(&raw_style.font_features),
font_variations: self.resolve_variations(raw_style.font_variations.as_ref()),
font_features: self.resolve_features(raw_style.font_features.as_ref()),
locale: raw_style
.locale
.and_then(|v| icu_locale_core::Locale::try_from_str(v).map(|v| v.id).ok()),
Expand Down Expand Up @@ -262,19 +266,10 @@ impl ResolveContext {
/// Resolves font variation settings.
pub(crate) fn resolve_variations(
&mut self,
variations: &FontVariations<'_>,
variations: &[FontVariation],
) -> Resolved<FontVariation> {
match variations {
FontVariations::Source(source) => {
self.tmp_variations.clear();
self.tmp_variations
.extend(FontVariation::parse_css_list(source).map_while(Result::ok));
}
FontVariations::List(settings) => {
self.tmp_variations.clear();
self.tmp_variations.extend_from_slice(settings);
}
}
self.tmp_variations.clear();
self.tmp_variations.extend_from_slice(variations);
if self.tmp_variations.is_empty() {
return Resolved::default();
}
Expand All @@ -285,21 +280,9 @@ impl ResolveContext {
}

/// Resolves font feature settings.
pub(crate) fn resolve_features(
&mut self,
features: &FontFeatures<'_>,
) -> Resolved<FontFeature> {
match features {
FontFeatures::Source(source) => {
self.tmp_features.clear();
self.tmp_features
.extend(FontFeature::parse_css_list(source).map_while(Result::ok));
}
FontFeatures::List(settings) => {
self.tmp_features.clear();
self.tmp_features.extend_from_slice(settings);
}
}
pub(crate) fn resolve_features(&mut self, features: &[FontFeature]) -> Resolved<FontFeature> {
self.tmp_features.clear();
self.tmp_features.extend_from_slice(features);
if self.tmp_features.is_empty() {
return Resolved::default();
}
Expand Down
6 changes: 0 additions & 6 deletions parley/src/setting.rs

This file was deleted.

134 changes: 104 additions & 30 deletions parley/src/style/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,74 +3,148 @@

use alloc::borrow::Cow;

pub use crate::setting::{FontFeature, FontVariation};
pub use fontique::{FontStyle, FontWeight, FontWidth, GenericFamily};
pub use text_primitives::{FontFamily, FontFamilyName};
pub use text_primitives::{FontFamily, FontFamilyName, FontFeature, FontVariation, Tag};

/// Font variation settings that can be supplied as a raw source string or a parsed slice.
/// Font variation settings (OpenType axis values).
///
/// Parley requires typed settings; if you have CSS-like strings, parse them up-front with
/// [`FontVariation::parse_css_list`] and then pass the resulting slice to Parley.
///
/// ```
/// # use parley::{FontVariation, FontVariations, StyleProperty};
/// #
/// let variations_vec: Vec<_> = FontVariation::parse_css_list(r#""wght" 700, "wdth" 125.5"#)
/// .collect::<Result<_, _>>()
/// .unwrap();
///
/// let property: StyleProperty<'_, ()> = variations_vec.as_slice().into();
/// ```
#[derive(Clone, PartialEq, Debug)]
pub enum FontVariations<'a> {
/// Setting source in CSS format.
Source(Cow<'a, str>),
/// List of settings.
List(Cow<'a, [FontVariation]>),
}
pub struct FontVariations<'a>(Cow<'a, [FontVariation]>);

impl<'a> FontVariations<'a> {
/// Creates an empty list of font variations.
#[inline]
pub const fn empty() -> Self {
Self::List(Cow::Borrowed(&[]))
Self(Cow::Borrowed(&[]))
}
}

impl<'a> From<&'a str> for FontVariations<'a> {
fn from(value: &'a str) -> Self {
Self::Source(Cow::Borrowed(value))
/// Returns the settings as a slice.
#[inline]
pub fn as_slice(&self) -> &[FontVariation] {
self.0.as_ref()
}
}

impl<'a> From<&'a [FontVariation]> for FontVariations<'a> {
fn from(value: &'a [FontVariation]) -> Self {
Self::List(Cow::Borrowed(value))
Self(Cow::Borrowed(value))
}
}

impl<'a, const N: usize> From<&'a [FontVariation; N]> for FontVariations<'a> {
fn from(value: &'a [FontVariation; N]) -> Self {
Self::List(Cow::Borrowed(&value[..]))
Self(Cow::Borrowed(&value[..]))
}
}

/// Font feature settings that can be supplied as a raw source string or a parsed slice.
#[derive(Clone, PartialEq, Debug)]
pub enum FontFeatures<'a> {
/// Setting source in CSS format.
Source(Cow<'a, str>),
/// List of settings.
List(Cow<'a, [FontFeature]>),
impl AsRef<[FontVariation]> for FontVariations<'_> {
#[inline]
fn as_ref(&self) -> &[FontVariation] {
self.0.as_ref()
}
}

/// Font feature settings (OpenType feature values).
///
/// Parley requires typed settings; if you have CSS-like strings, parse them up-front with
/// [`FontFeature::parse_css_list`] and then pass the resulting slice to Parley.
///
/// ```
/// # use parley::{FontFeature, FontFeatures, StyleProperty};
/// #
/// let features_vec: Vec<_> = FontFeature::parse_css_list(r#""liga" on, "kern" off, "salt" 3"#)
/// .collect::<Result<_, _>>()
/// .unwrap();
///
/// let property: StyleProperty<'_, ()> = features_vec.as_slice().into();
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct FontFeatures<'a>(Cow<'a, [FontFeature]>);

impl<'a> FontFeatures<'a> {
/// Creates an empty list of font features.
#[inline]
pub const fn empty() -> Self {
Self::List(Cow::Borrowed(&[]))
Self(Cow::Borrowed(&[]))
}
}

impl<'a> From<&'a str> for FontFeatures<'a> {
fn from(value: &'a str) -> Self {
Self::Source(Cow::Borrowed(value))
/// Returns the settings as a slice.
#[inline]
pub fn as_slice(&self) -> &[FontFeature] {
self.0.as_ref()
}
}

impl<'a> From<&'a [FontFeature]> for FontFeatures<'a> {
fn from(value: &'a [FontFeature]) -> Self {
Self::List(Cow::Borrowed(value))
Self(Cow::Borrowed(value))
}
}

impl<'a, const N: usize> From<&'a [FontFeature; N]> for FontFeatures<'a> {
fn from(value: &'a [FontFeature; N]) -> Self {
Self::List(Cow::Borrowed(&value[..]))
Self(Cow::Borrowed(&value[..]))
}
}

impl AsRef<[FontFeature]> for FontFeatures<'_> {
#[inline]
fn as_ref(&self) -> &[FontFeature] {
self.0.as_ref()
}
}

#[cfg(test)]
mod tests {
extern crate alloc;

use alloc::vec::Vec;

use super::{FontFeature, FontFeatures, FontVariation, FontVariations};
use crate::StyleProperty;

#[test]
fn opentype_settings_from_parse_css_list() {
let features_vec: Vec<_> =
FontFeature::parse_css_list(r#""liga" on, "kern" off, "salt" 3"#)
.collect::<Result<_, _>>()
.unwrap();
let variations_vec: Vec<_> = FontVariation::parse_css_list(r#""wght" 700, "wdth" 125.5"#)
.collect::<Result<_, _>>()
.unwrap();

let features = FontFeatures::from(features_vec.as_slice());
let variations = FontVariations::from(variations_vec.as_slice());

let features_prop: StyleProperty<'_, ()> = features.clone().into();
let variations_prop: StyleProperty<'_, ()> = variations.clone().into();

assert_eq!(features.as_ref(), features_vec.as_slice());
assert_eq!(variations.as_ref(), variations_vec.as_slice());

match features_prop {
StyleProperty::FontFeatures(list) => {
assert_eq!(list.as_ref(), features_vec.as_slice());
}
_ => panic!("expected StyleProperty::FontFeatures"),
}
match variations_prop {
StyleProperty::FontVariations(list) => {
assert_eq!(list.as_ref(), variations_vec.as_slice());
}
_ => panic!("expected StyleProperty::FontVariations"),
}
}
}
32 changes: 31 additions & 1 deletion parley/src/style/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use alloc::borrow::Cow;
pub use brush::*;
pub use font::{
FontFamily, FontFamilyName, FontFeature, FontFeatures, FontStyle, FontVariation,
FontVariations, FontWeight, FontWidth, GenericFamily,
FontVariations, FontWeight, FontWidth, GenericFamily, Tag,
};
pub use styleset::StyleSet;
pub use text_primitives::{OverflowWrap, TextWrapMode, WordBreak};
Expand Down Expand Up @@ -218,17 +218,47 @@ impl<'a, B: Brush> From<FontFamilyName<'a>> for StyleProperty<'a, B> {
}

impl<'a, B: Brush> From<FontVariations<'a>> for StyleProperty<'a, B> {
#[inline]
fn from(value: FontVariations<'a>) -> Self {
StyleProperty::FontVariations(value)
}
}

impl<'a, B: Brush> From<&'a [FontVariation]> for StyleProperty<'a, B> {
#[inline]
fn from(value: &'a [FontVariation]) -> Self {
StyleProperty::FontVariations(value.into())
}
}

impl<'a, B: Brush, const N: usize> From<&'a [FontVariation; N]> for StyleProperty<'a, B> {
#[inline]
fn from(value: &'a [FontVariation; N]) -> Self {
StyleProperty::FontVariations(value.into())
}
}

impl<'a, B: Brush> From<FontFeatures<'a>> for StyleProperty<'a, B> {
#[inline]
fn from(value: FontFeatures<'a>) -> Self {
StyleProperty::FontFeatures(value)
}
}

impl<'a, B: Brush> From<&'a [FontFeature]> for StyleProperty<'a, B> {
#[inline]
fn from(value: &'a [FontFeature]) -> Self {
StyleProperty::FontFeatures(value.into())
}
}

impl<'a, B: Brush, const N: usize> From<&'a [FontFeature; N]> for StyleProperty<'a, B> {
#[inline]
fn from(value: &'a [FontFeature; N]) -> Self {
StyleProperty::FontFeatures(value.into())
}
}

impl<B: Brush> From<GenericFamily> for StyleProperty<'_, B> {
fn from(f: GenericFamily) -> Self {
StyleProperty::FontFamily(f.into())
Expand Down
23 changes: 10 additions & 13 deletions parley/src/tests/test_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use peniko::{
use super::utils::{
ColorBrush, FONT_FAMILY_LIST, TestEnv, asserts::assert_eq_layout_data_alignments,
};
use crate::setting::{FontFeature, FontVariation};
use crate::{
Alignment, AlignmentOptions, ContentWidths, FontFamily, FontFeatures, FontVariations,
InlineBox, Layout, LineHeight, StyleProperty, TextStyle, WhiteSpaceCollapse, test_name,
Alignment, AlignmentOptions, ContentWidths, FontFamily, InlineBox, Layout, LineHeight,
StyleProperty, TextStyle, WhiteSpaceCollapse, test_name,
};
use crate::{FontFeature, FontVariation, Tag};

#[test]
fn plain_multiline_text() {
Expand Down Expand Up @@ -613,17 +613,17 @@ fn font_features() {
let text = "fi ".repeat(4);
let mut builder = env.ranged_builder(&text);
builder.push(
FontFeatures::from(&[FontFeature {
tag: crate::setting::Tag::new(b"liga"),
&[FontFeature {
tag: Tag::new(b"liga"),
value: 1,
}]),
}],
0..5,
);
builder.push(
FontFeatures::from(&[FontFeature {
tag: crate::setting::Tag::new(b"liga"),
&[FontFeature {
tag: Tag::new(b"liga"),
value: 0,
}]),
}],
5..10,
);
let mut layout = builder.build(&text);
Expand All @@ -641,10 +641,7 @@ fn variable_fonts() {
for wght in [100., 500., 1000.] {
let mut builder = env.ranged_builder(text);
builder.push_default(FontFamily::named("Arimo"));
builder.push_default(FontVariations::from(&[FontVariation::new(
crate::setting::Tag::new(b"wght"),
wght,
)]));
builder.push_default(&[FontVariation::new(Tag::new(b"wght"), wght)]);
let mut layout = builder.build(text);
layout.break_all_lines(Some(100.0));
layout.align(None, Alignment::Start, AlignmentOptions::default());
Expand Down
3 changes: 3 additions & 0 deletions text_primitives/src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
use core::fmt;

/// A 4-byte OpenType tag (for example `wght`, `liga`).
///
/// This is used by [`FontFeature`] and [`FontVariation`] to identify the OpenType feature or axis
/// being configured.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct Tag([u8; 4]);
Expand Down