Skip to content

Commit

Permalink
CoWify style types (#128)
Browse files Browse the repository at this point in the history
This:
- Converts parley style types to use `std::borrow::Cow` instead of
references
- Removes the lifetime parameter from `PlainEditor` and `PlainEditorOp`
by making them using `StyleProperty<'static>`

This isn't ideal from an API point of view, but does at least allow
`PlainEditor` to be stored within a struct.

It would be an option to leave the lifetime parameter in `PlainEditor`
and make uses who want to store it in a struct specify
`PlainEditor<'static>` themselves. I have not done so because I don't
think there's much use for the borrowed editor outside of toy examples.
  • Loading branch information
nicoburns authored Oct 9, 2024
1 parent a05a6f1 commit d4dcf36
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 51 deletions.
5 changes: 3 additions & 2 deletions examples/swash_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<Color> = StyleProperty::FontStack(font_stack);
let font_stack = FontStack::Source(Cow::Borrowed("system-ui"));
let font_stack_style: StyleProperty<Color> = StyleProperty::FontStack(font_stack.clone());
let bold = FontWeight::new(600.0);
let bold_style = StyleProperty::FontWeight(bold);

Expand Down
4 changes: 3 additions & 1 deletion examples/tiny_skia_render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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));
Expand Down
5 changes: 3 additions & 2 deletions examples/vello_editor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -48,7 +49,7 @@ struct SimpleVelloApp<'s> {
scene: Scene,

// Our text state object
editor: text::Editor<'s>,
editor: text::Editor,
}

impl ApplicationHandler for SimpleVelloApp<'_> {
Expand Down Expand Up @@ -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"),
)),
])),
]);
Expand Down
8 changes: 4 additions & 4 deletions examples/vello_editor/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ 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<Color>,
editor: PlainEditor<'a, Color>,
editor: PlainEditor<Color>,
last_click_time: Option<Instant>,
click_count: u32,
pointer_down: bool,
cursor_pos: (f32, f32),
modifiers: Option<Modifiers>,
}

impl<'a> Editor<'a> {
pub fn transact(&mut self, t: impl IntoIterator<Item = PlainEditorOp<'a, Color>>) {
impl Editor {
pub fn transact(&mut self, t: impl IntoIterator<Item = PlainEditorOp<Color>>) {
self.editor
.transact(&mut self.font_cx, &mut self.layout_cx, t);
}
Expand Down
14 changes: 7 additions & 7 deletions parley/src/layout/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>
where
T: Brush + Clone + Debug + PartialEq + Default,
{
default_style: Arc<[StyleProperty<'a, T>]>,
default_style: Arc<[StyleProperty<'static, T>]>,
buffer: String,
layout: Layout<T>,
selection: Selection,
Expand All @@ -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<T> Default for PlainEditor<T>
where
T: Brush + Clone + Debug + PartialEq + Default,
{
Expand All @@ -55,7 +55,7 @@ where

/// Operations on a `PlainEditor` for `PlainEditor::transact`
#[non_exhaustive]
pub enum PlainEditorOp<'a, T>
pub enum PlainEditorOp<T>
where
T: Brush + Clone + Debug + PartialEq + Default,
{
Expand All @@ -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<str>),
/// Delete the selection
Expand Down Expand Up @@ -133,7 +133,7 @@ where
ExtendSelectionToPoint(f32, f32),
}

impl<'a, T> PlainEditor<'a, T>
impl<T> PlainEditor<T>
where
T: Brush + Clone + Debug + PartialEq + Default,
{
Expand All @@ -142,7 +142,7 @@ where
&mut self,
font_cx: &mut FontContext,
layout_cx: &mut LayoutContext<T>,
t: impl IntoIterator<Item = PlainEditorOp<'a, T>>,
t: impl IntoIterator<Item = PlainEditorOp<T>>,
) {
let mut layout_after = false;

Expand Down
28 changes: 17 additions & 11 deletions parley/src/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -134,13 +135,13 @@ impl ResolveContext {
) -> ResolvedProperty<B> {
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),
Expand All @@ -166,13 +167,13 @@ impl ResolveContext {
scale: f32,
) -> ResolvedStyle<B> {
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 {
Expand All @@ -194,14 +195,18 @@ impl ResolveContext {
}

/// Resolves a font stack.
pub fn resolve_stack(&mut self, fcx: &mut FontContext, stack: FontStack) -> Resolved<FamilyId> {
pub fn resolve_stack(
&mut self,
fcx: &mut FontContext,
stack: &FontStack,
) -> Resolved<FamilyId> {
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());
}
}
Expand All @@ -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) => {
Expand All @@ -247,7 +253,7 @@ impl ResolveContext {
/// Resolves font variation settings.
pub fn resolve_variations(
&mut self,
variations: FontSettings<FontVariation>,
variations: &FontSettings<FontVariation>,
) -> Resolved<Setting<f32>> {
match variations {
FontSettings::Source(source) => {
Expand All @@ -272,7 +278,7 @@ impl ResolveContext {
/// Resolves font feature settings.
pub fn resolve_features(
&mut self,
features: FontSettings<FontFeature>,
features: &FontSettings<FontFeature>,
) -> Resolved<Setting<u16>> {
match features {
FontSettings::Source(source) => {
Expand Down
58 changes: 37 additions & 21 deletions parley/src/style/font.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -16,23 +18,23 @@ pub type FontFeature = swash::Setting<u16>;
/// Prioritized sequence of font families.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/font-family>
#[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.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/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),
}
Expand All @@ -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> {
Self::parse_list(s).next()
Expand All @@ -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::<Vec<_>>();
/// 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);
/// ```
Expand Down Expand Up @@ -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 {
Expand All @@ -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))
}
}
Loading

0 comments on commit d4dcf36

Please sign in to comment.