diff --git a/examples/swash_render/src/main.rs b/examples/swash_render/src/main.rs index c5a11045..c95e6bf6 100644 --- a/examples/swash_render/src/main.rs +++ b/examples/swash_render/src/main.rs @@ -10,6 +10,7 @@ use parley::layout::{Alignment, Glyph, GlyphRun, Layout, PositionedLayoutItem}; use parley::style::{FontStack, FontWeight, StyleProperty, TextStyle}; use parley::{FontContext, InlineBox, LayoutContext}; use peniko::Color; +use std::borrow::Cow; use std::fs::File; use swash::scale::image::Content; use swash::scale::{Render, ScaleContext, Scaler, Source, StrikeWith}; @@ -46,8 +47,8 @@ fn main() { // Setup some Parley text styles let brush_style = StyleProperty::Brush(text_color); - let font_stack = FontStack::Source("system-ui"); - let font_stack_style: StyleProperty = StyleProperty::FontStack(font_stack); + let font_stack = FontStack::Source(Cow::Borrowed("system-ui")); + let font_stack_style: StyleProperty = StyleProperty::FontStack(font_stack.clone()); let bold = FontWeight::new(600.0); let bold_style = StyleProperty::FontWeight(bold); diff --git a/examples/tiny_skia_render/src/main.rs b/examples/tiny_skia_render/src/main.rs index 7f322055..a1690ec4 100644 --- a/examples/tiny_skia_render/src/main.rs +++ b/examples/tiny_skia_render/src/main.rs @@ -7,6 +7,8 @@ //! Note: Emoji rendering is not currently implemented in this example. See the swash example //! if you need emoji rendering. +use std::borrow::Cow; + use parley::layout::{Alignment, GlyphRun, Layout, PositionedLayoutItem}; use parley::style::{FontStack, FontWeight, StyleProperty}; use parley::{FontContext, InlineBox, LayoutContext}; @@ -53,7 +55,7 @@ fn main() { builder.push_default(&brush_style); // Set default font family - let font_stack = FontStack::Source("system-ui"); + let font_stack = FontStack::Source(Cow::Borrowed("system-ui")); let font_stack_style = StyleProperty::FontStack(font_stack); builder.push_default(&font_stack_style); builder.push_default(&StyleProperty::LineHeight(1.3)); diff --git a/examples/vello_editor/src/main.rs b/examples/vello_editor/src/main.rs index 66e0451a..3ec0e372 100644 --- a/examples/vello_editor/src/main.rs +++ b/examples/vello_editor/src/main.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use anyhow::Result; +use std::borrow::Cow; use std::num::NonZeroUsize; use std::sync::Arc; use vello::peniko::Color; @@ -48,7 +49,7 @@ struct SimpleVelloApp<'s> { scene: Scene, // Our text state object - editor: text::Editor<'s>, + editor: text::Editor, } impl ApplicationHandler for SimpleVelloApp<'_> { @@ -135,7 +136,7 @@ impl ApplicationHandler for SimpleVelloApp<'_> { parley::style::StyleProperty::FontSize(32.0), parley::style::StyleProperty::LineHeight(1.2), parley::style::StyleProperty::FontStack(parley::style::FontStack::Source( - "system-ui", + Cow::Borrowed("system-ui"), )), ])), ]); diff --git a/examples/vello_editor/src/text.rs b/examples/vello_editor/src/text.rs index 843f313a..feeaea5a 100644 --- a/examples/vello_editor/src/text.rs +++ b/examples/vello_editor/src/text.rs @@ -20,10 +20,10 @@ use parley::{FontContext, LayoutContext, PlainEditor, PlainEditorOp}; pub const INSET: f32 = 32.0; #[derive(Default)] -pub struct Editor<'a> { +pub struct Editor { font_cx: FontContext, layout_cx: LayoutContext, - editor: PlainEditor<'a, Color>, + editor: PlainEditor, last_click_time: Option, click_count: u32, pointer_down: bool, @@ -31,8 +31,8 @@ pub struct Editor<'a> { modifiers: Option, } -impl<'a> Editor<'a> { - pub fn transact(&mut self, t: impl IntoIterator>) { +impl Editor { + pub fn transact(&mut self, t: impl IntoIterator>) { self.editor .transact(&mut self.font_cx, &mut self.layout_cx, t); } diff --git a/parley/src/layout/editor.rs b/parley/src/layout/editor.rs index 4c57123b..248a5247 100644 --- a/parley/src/layout/editor.rs +++ b/parley/src/layout/editor.rs @@ -22,11 +22,11 @@ pub enum ActiveText<'a> { } /// Basic plain text editor with a single default style. -pub struct PlainEditor<'a, T> +pub struct PlainEditor where T: Brush + Clone + Debug + PartialEq + Default, { - default_style: Arc<[StyleProperty<'a, T>]>, + default_style: Arc<[StyleProperty<'static, T>]>, buffer: String, layout: Layout, selection: Selection, @@ -36,7 +36,7 @@ where } // TODO: When MSRV >= 1.80 we can remove this. Default was not implemented for Arc<[T]> where T: !Default until 1.80 -impl<'a, T> Default for PlainEditor<'a, T> +impl Default for PlainEditor where T: Brush + Clone + Debug + PartialEq + Default, { @@ -55,7 +55,7 @@ where /// Operations on a `PlainEditor` for `PlainEditor::transact` #[non_exhaustive] -pub enum PlainEditorOp<'a, T> +pub enum PlainEditorOp where T: Brush + Clone + Debug + PartialEq + Default, { @@ -66,7 +66,7 @@ where /// Set the scale for the layout SetScale(f32), /// Set the default style for the layout - SetDefaultStyle(Arc<[StyleProperty<'a, T>]>), + SetDefaultStyle(Arc<[StyleProperty<'static, T>]>), /// Insert at cursor, or replace selection InsertOrReplaceSelection(Arc), /// Delete the selection @@ -133,7 +133,7 @@ where ExtendSelectionToPoint(f32, f32), } -impl<'a, T> PlainEditor<'a, T> +impl PlainEditor where T: Brush + Clone + Debug + PartialEq + Default, { @@ -142,7 +142,7 @@ where &mut self, font_cx: &mut FontContext, layout_cx: &mut LayoutContext, - t: impl IntoIterator>, + t: impl IntoIterator>, ) { let mut layout_after = false; diff --git a/parley/src/resolve/mod.rs b/parley/src/resolve/mod.rs index 16af7fb9..055b21c5 100644 --- a/parley/src/resolve/mod.rs +++ b/parley/src/resolve/mod.rs @@ -19,6 +19,7 @@ use crate::font::FontContext; use crate::layout; use crate::style::TextStyle; use crate::util::nearly_eq; +use core::borrow::Borrow; use core::ops::Range; use fontique::FamilyId; use swash::text::Language; @@ -134,13 +135,13 @@ impl ResolveContext { ) -> ResolvedProperty { use ResolvedProperty::*; match property { - StyleProperty::FontStack(value) => FontStack(self.resolve_stack(fcx, *value)), + StyleProperty::FontStack(value) => FontStack(self.resolve_stack(fcx, value)), StyleProperty::FontSize(value) => FontSize(*value * scale), StyleProperty::FontStretch(value) => FontStretch(*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)), + StyleProperty::FontFeatures(value) => FontFeatures(self.resolve_features(value)), StyleProperty::Locale(value) => Locale(value.map(Language::parse).flatten()), StyleProperty::Brush(value) => Brush(value.clone()), StyleProperty::Underline(value) => Underline(*value), @@ -166,13 +167,13 @@ impl ResolveContext { scale: f32, ) -> ResolvedStyle { ResolvedStyle { - font_stack: self.resolve_stack(fcx, raw_style.font_stack), + font_stack: self.resolve_stack(fcx, &raw_style.font_stack), font_size: raw_style.font_size * scale, font_stretch: raw_style.font_stretch, 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), + font_features: self.resolve_features(&raw_style.font_features), locale: raw_style.locale.and_then(Language::parse), brush: raw_style.brush.clone(), underline: ResolvedDecoration { @@ -194,14 +195,18 @@ impl ResolveContext { } /// Resolves a font stack. - pub fn resolve_stack(&mut self, fcx: &mut FontContext, stack: FontStack) -> Resolved { + pub fn resolve_stack( + &mut self, + fcx: &mut FontContext, + stack: &FontStack, + ) -> Resolved { self.tmp_families.clear(); match stack { FontStack::Source(source) => { for family in FontFamily::parse_list(source) { match family { FontFamily::Named(name) => { - if let Some(family) = fcx.collection.family_by_name(name) { + if let Some(family) = fcx.collection.family_by_name(&name) { self.tmp_families.push(family.id()); } } @@ -220,10 +225,11 @@ impl ResolveContext { } FontFamily::Generic(family) => { self.tmp_families - .extend(fcx.collection.generic_families(family)); + .extend(fcx.collection.generic_families(*family)); } }, FontStack::List(families) => { + let families: &[FontFamily<'_>] = families.borrow(); for family in families { match family { FontFamily::Named(name) => { @@ -247,7 +253,7 @@ impl ResolveContext { /// Resolves font variation settings. pub fn resolve_variations( &mut self, - variations: FontSettings, + variations: &FontSettings, ) -> Resolved> { match variations { FontSettings::Source(source) => { @@ -272,7 +278,7 @@ impl ResolveContext { /// Resolves font feature settings. pub fn resolve_features( &mut self, - features: FontSettings, + features: &FontSettings, ) -> Resolved> { match features { FontSettings::Source(source) => { diff --git a/parley/src/style/font.rs b/parley/src/style/font.rs index c84cced9..8101a30b 100644 --- a/parley/src/style/font.rs +++ b/parley/src/style/font.rs @@ -1,6 +1,8 @@ // Copyright 2021 the Parley Authors // SPDX-License-Identifier: Apache-2.0 OR MIT +use alloc::borrow::Cow; +use alloc::borrow::ToOwned; use core::fmt; pub use fontique::{ @@ -16,23 +18,23 @@ pub type FontFeature = swash::Setting; /// Prioritized sequence of font families. /// /// -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum FontStack<'a> { /// Font family list in CSS format. - Source(&'a str), + Source(Cow<'a, str>), /// Single font family. Single(FontFamily<'a>), /// Ordered list of font families. - List(&'a [FontFamily<'a>]), + List(Cow<'a, [FontFamily<'a>]>), } /// Named or generic font family. /// /// -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum FontFamily<'a> { /// Named font family. - Named(&'a str), + Named(Cow<'a, str>), /// Generic font family. Generic(GenericFamily), } @@ -44,13 +46,14 @@ impl<'a> FontFamily<'a> { /// ``` /// use parley::style::FontFamily::{self, *}; /// use parley::style::GenericFamily::*; + /// use std::borrow::Cow; /// - /// assert_eq!(FontFamily::parse("Palatino Linotype"), Some(Named("Palatino Linotype"))); + /// assert_eq!(FontFamily::parse("Palatino Linotype"), Some(Named(Cow::Borrowed("Palatino Linotype")))); /// assert_eq!(FontFamily::parse("monospace"), Some(Generic(Monospace))); /// /// // Note that you can quote a generic family to capture it as a named family: /// - /// assert_eq!(FontFamily::parse("'monospace'"), Some(Named("monospace"))); + /// assert_eq!(FontFamily::parse("'monospace'"), Some(Named(Cow::Borrowed("monospace")))); /// ``` pub fn parse(s: &'a str) -> Option { Self::parse_list(s).next() @@ -62,11 +65,12 @@ impl<'a> FontFamily<'a> { /// ``` /// use parley::style::FontFamily::{self, *}; /// use parley::style::GenericFamily::*; + /// use std::borrow::Cow; /// /// let source = "Arial, 'Times New Roman', serif"; /// /// let parsed_families = FontFamily::parse_list(source).collect::>(); - /// let families = vec![Named("Arial"), Named("Times New Roman"), Generic(Serif)]; + /// let families = vec![Named(Cow::Borrowed("Arial")), Named(Cow::Borrowed("Times New Roman")), Generic(Serif)]; /// /// assert_eq!(parsed_families, families); /// ``` @@ -125,20 +129,20 @@ impl<'a> Iterator for ParseList<'a> { while pos < self.len { if self.source[pos] == quote { self.pos = pos + 1; - return Some(FontFamily::Named( + return Some(FontFamily::Named(Cow::Borrowed( core::str::from_utf8(self.source.get(start..pos)?) .ok()? .trim(), - )); + ))); } pos += 1; } self.pos = pos; - return Some(FontFamily::Named( + return Some(FontFamily::Named(Cow::Borrowed( core::str::from_utf8(self.source.get(start..pos)?) .ok()? .trim(), - )); + ))); } let mut end = start; while pos < self.len { @@ -155,29 +159,41 @@ impl<'a> Iterator for ParseList<'a> { .trim(); Some(match GenericFamily::parse(name) { Some(family) => FontFamily::Generic(family), - _ => FontFamily::Named(name), + _ => FontFamily::Named(Cow::Borrowed(name)), }) } } /// Font settings that can be supplied as a raw source string or /// a parsed slice. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum FontSettings<'a, T> { +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum FontSettings<'a, T> +where + [T]: ToOwned, + <[T] as ToOwned>::Owned: fmt::Debug + Eq + Clone, +{ /// Setting source in CSS format. - Source(&'a str), + Source(Cow<'a, str>), /// List of settings. - List(&'a [T]), + List(Cow<'a, [T]>), } -impl<'a, T> From<&'a str> for FontSettings<'a, T> { +impl<'a, T> From<&'a str> for FontSettings<'a, T> +where + [T]: ToOwned, + <[T] as ToOwned>::Owned: fmt::Debug + Eq + Clone, +{ fn from(value: &'a str) -> Self { - Self::Source(value) + Self::Source(Cow::Borrowed(value)) } } -impl<'a, T> From<&'a [T]> for FontSettings<'a, T> { +impl<'a, T> From<&'a [T]> for FontSettings<'a, T> +where + [T]: ToOwned, + <[T] as ToOwned>::Owned: fmt::Debug + Eq + Clone, +{ fn from(value: &'a [T]) -> Self { - Self::List(value) + Self::List(Cow::Borrowed(value)) } } diff --git a/parley/src/style/mod.rs b/parley/src/style/mod.rs index f4289020..6efc1cb0 100644 --- a/parley/src/style/mod.rs +++ b/parley/src/style/mod.rs @@ -6,6 +6,8 @@ mod brush; mod font; +use alloc::borrow::Cow; + pub use brush::*; pub use font::{ FontFamily, FontFeature, FontSettings, FontStack, FontStretch, FontStyle, FontVariation, @@ -111,13 +113,13 @@ pub struct TextStyle<'a, B: Brush> { impl Default for TextStyle<'_, B> { fn default() -> Self { TextStyle { - font_stack: FontStack::Source("sans-serif"), + font_stack: FontStack::Source(Cow::Borrowed("sans-serif")), font_size: 16.0, font_stretch: Default::default(), font_style: Default::default(), font_weight: Default::default(), - font_variations: FontSettings::List(&[]), - font_features: FontSettings::List(&[]), + font_variations: FontSettings::List(Cow::Borrowed(&[])), + font_features: FontSettings::List(Cow::Borrowed(&[])), locale: Default::default(), brush: Default::default(), has_underline: Default::default(),