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
276 changes: 229 additions & 47 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ license.workspace = true

[workspace.dependencies]
peniko = { version = "0.6.0", features = ["serde"] }
parley = { version = "0.7.0" }
fontique = { version = "0.7.0" }
parley = { version = "0.11.0" }
serde = { version = "1.0" }
serde_json = { version = "1.0" }
lapce-xi-rope = "0.4.0"
Expand Down Expand Up @@ -84,6 +83,7 @@ unicode-segmentation = { workspace = true }
peniko = { workspace = true }
imbl.workspace = true
parley = { workspace = true }
swash = { workspace = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true }
lapce-xi-rope = { workspace = true, optional = true }
Expand Down
1 change: 0 additions & 1 deletion renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ parking_lot = { workspace = true }
peniko = { workspace = true }
resvg = { workspace = true }
parley = { workspace = true }
fontique = { workspace = true }
winit = { workspace = true }
wgpu = { workspace = true }
crossbeam = { version = "0.8", optional = true }
Expand Down
93 changes: 46 additions & 47 deletions renderer/src/text/attrs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::borrow::Cow;
use std::ops::Range;

use crate::text::TextBrush;
use crate::text::{FontStyle, FontWeight, FontWidth};
use fontique::GenericFamily;
use parley::style::{FontFamily, FontStack, StyleProperty, WordBreakStrength};
use parley::FontFamilyName;
use parley::style::{FontFamily, GenericFamily, StyleProperty, WordBreak};
use peniko::Color;

/// An owned font family identifier.
Expand Down Expand Up @@ -68,39 +69,37 @@ impl FamilyOwned {
}
}

/// Converts this owned family to a borrowed Parley [`FontFamily`] reference.
fn to_font_family(&self) -> FontFamily<'_> {
/// Converts this owned family to a borrowed Parley [`FontFamilyName`] reference.
fn to_font_family_name(&self) -> FontFamilyName<'_> {
match self {
FamilyOwned::Name(name) => FontFamily::Named(std::borrow::Cow::Borrowed(name.as_str())),
FamilyOwned::Serif => FontFamily::Generic(GenericFamily::Serif),
FamilyOwned::SansSerif => FontFamily::Generic(GenericFamily::SansSerif),
FamilyOwned::Cursive => FontFamily::Generic(GenericFamily::Cursive),
FamilyOwned::Fantasy => FontFamily::Generic(GenericFamily::Fantasy),
FamilyOwned::Monospace => FontFamily::Generic(GenericFamily::Monospace),
FamilyOwned::Name(name) => FontFamilyName::Named(Cow::Borrowed(name.as_str())),
FamilyOwned::Serif => FontFamilyName::Generic(GenericFamily::Serif),
FamilyOwned::SansSerif => FontFamilyName::Generic(GenericFamily::SansSerif),
FamilyOwned::Cursive => FontFamilyName::Generic(GenericFamily::Cursive),
FamilyOwned::Fantasy => FontFamilyName::Generic(GenericFamily::Fantasy),
FamilyOwned::Monospace => FontFamilyName::Generic(GenericFamily::Monospace),
}
}

/// Converts a slice of owned families into a Parley [`FontStack`].
/// Converts a slice of owned families into a Parley [`FontFamily`].
///
/// For a single named family, this produces a [`FontStack::Source`] so that
/// For a single named family, this produces a [`FontFamily::Source`] so that
/// Parley can parse comma-separated fallbacks within the name string.
/// For a single generic family, it produces [`FontStack::Single`].
/// For multiple families, it produces [`FontStack::List`] preserving the
/// For a single generic family, it produces [`FontFamily::Single`].
/// For multiple families, it produces [`FontFamily::List`] preserving the
/// full fallback chain.
/// An empty slice defaults to sans-serif.
pub fn to_font_stack(families: &[FamilyOwned]) -> FontStack<'_> {
pub fn to_font_family(families: &[FamilyOwned]) -> FontFamily<'_> {
match families {
[] => FontStack::Single(FontFamily::Generic(GenericFamily::SansSerif)),
[] => FontFamily::Single(FontFamilyName::Generic(GenericFamily::SansSerif)),
[single] => match single {
FamilyOwned::Name(name) => {
FontStack::Source(std::borrow::Cow::Borrowed(name.as_str()))
}
other => FontStack::Single(other.to_font_family()),
FamilyOwned::Name(name) => FontFamily::Source(Cow::Borrowed(name.as_str())),
other => FontFamily::Single(other.to_font_family_name()),
},
multiple => {
let list: Vec<FontFamily<'_>> =
multiple.iter().map(|f| f.to_font_family()).collect();
FontStack::List(std::borrow::Cow::Owned(list))
let list: Vec<FontFamilyName<'_>> =
multiple.iter().map(|f| f.to_font_family_name()).collect();
FontFamily::List(Cow::Owned(list))
}
}
}
Expand Down Expand Up @@ -203,7 +202,7 @@ pub struct Attrs<'a> {
/// Font width / stretch (e.g. condensed, expanded), or `None` for normal.
font_width: Option<FontWidth>,
/// Word break strength used during wrapping, or `None` for Parley's default.
word_break: Option<WordBreakStrength>,
word_break: Option<WordBreak>,
/// Application-defined metadata carried through layout without interpretation.
metadata: Option<usize>,
}
Expand Down Expand Up @@ -272,8 +271,8 @@ impl<'a> Attrs<'a> {
self
}

/// Sets the word break strength used when text wrapping is enabled.
pub fn word_break(mut self, word_break: WordBreakStrength) -> Self {
/// Sets the word break used when text wrapping is enabled.
pub fn word_break(mut self, word_break: WordBreak) -> Self {
self.word_break = Some(word_break);
self
}
Expand Down Expand Up @@ -323,8 +322,8 @@ impl<'a> Attrs<'a> {
self.font_width
}

/// Returns the word break strength, or `None` if unset.
pub fn get_word_break(&self) -> Option<WordBreakStrength> {
/// Returns the word break, or `None` if unset.
pub fn get_word_break(&self) -> Option<WordBreak> {
self.word_break
}

Expand Down Expand Up @@ -360,8 +359,8 @@ impl<'a> Attrs<'a> {
builder.push_default(StyleProperty::Brush(TextBrush(color)));
}
if let Some(family) = self.family {
let stack = FamilyOwned::to_font_stack(family);
builder.push_default(StyleProperty::FontStack(stack));
let family = FamilyOwned::to_font_family(family);
builder.push_default(StyleProperty::FontFamily(family));
}
if let Some(weight) = self.weight {
builder.push_default(StyleProperty::FontWeight(weight));
Expand Down Expand Up @@ -403,8 +402,8 @@ impl<'a> Attrs<'a> {
builder.push(StyleProperty::Brush(TextBrush(color)), range.clone());
}
if let Some(family) = self.family {
let stack = FamilyOwned::to_font_stack(family);
builder.push(StyleProperty::FontStack(stack), range.clone());
let stack = FamilyOwned::to_font_family(family);
builder.push(StyleProperty::FontFamily(stack), range.clone());
}
if let Some(weight) = self.weight {
builder.push(StyleProperty::FontWeight(weight), range.clone());
Expand Down Expand Up @@ -454,8 +453,8 @@ pub struct AttrsOwned {
style: Option<FontStyle>,
/// Font width / stretch (e.g. condensed, expanded), or `None` for normal.
font_width: Option<FontWidth>,
/// Word break strength used during wrapping, or `None` for Parley's default.
word_break: Option<WordBreakStrength>,
/// Word break used during wrapping, or `None` for Parley's default.
word_break: Option<WordBreak>,
/// Application-defined metadata carried through layout without interpretation.
metadata: Option<usize>,
}
Expand Down Expand Up @@ -789,15 +788,15 @@ mod tests {
#[test]
fn to_font_stack_single_named() {
let families = vec![FamilyOwned::Name("Inter".to_string())];
let stack = FamilyOwned::to_font_stack(&families);
assert!(matches!(stack, FontStack::Source(_)));
let stack = FamilyOwned::to_font_family(&families);
assert!(matches!(stack, FontFamily::Source(_)));
}

#[test]
fn to_font_stack_single_generic() {
let families = vec![FamilyOwned::Monospace];
let stack = FamilyOwned::to_font_stack(&families);
assert!(matches!(stack, FontStack::Single(_)));
let stack = FamilyOwned::to_font_family(&families);
assert!(matches!(stack, FontFamily::Single(_)));
}

#[test]
Expand All @@ -807,18 +806,18 @@ mod tests {
FamilyOwned::Monospace,
FamilyOwned::SansSerif,
];
let stack = FamilyOwned::to_font_stack(&families);
let stack = FamilyOwned::to_font_family(&families);
match stack {
FontStack::List(list) => {
FontFamily::List(list) => {
assert_eq!(list.len(), 3, "all families should be preserved");
assert!(matches!(list[0], FontFamily::Named(_)));
assert!(matches!(list[0], FontFamilyName::Named(_)));
assert!(matches!(
list[1],
FontFamily::Generic(GenericFamily::Monospace)
FontFamilyName::Generic(GenericFamily::Monospace)
));
assert!(matches!(
list[2],
FontFamily::Generic(GenericFamily::SansSerif)
FontFamilyName::Generic(GenericFamily::SansSerif)
));
}
other => panic!("expected FontStack::List, got {other:?}"),
Expand All @@ -831,20 +830,20 @@ mod tests {
FamilyOwned::Name("Fira Code".to_string()),
FamilyOwned::Name("Cascadia Code".to_string()),
];
let stack = FamilyOwned::to_font_stack(&families);
let stack = FamilyOwned::to_font_family(&families);
assert!(
matches!(stack, FontStack::List(_)),
matches!(stack, FontFamily::List(_)),
"two families should produce List"
);
}

#[test]
fn to_font_stack_empty_defaults_to_sans_serif() {
let families: Vec<FamilyOwned> = vec![];
let stack = FamilyOwned::to_font_stack(&families);
let stack = FamilyOwned::to_font_family(&families);
assert!(matches!(
stack,
FontStack::Single(FontFamily::Generic(GenericFamily::SansSerif))
FontFamily::Single(FontFamilyName::Generic(GenericFamily::SansSerif))
));
}

Expand Down
4 changes: 2 additions & 2 deletions renderer/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//!
//! # Re-exports
//!
//! [`FontStyle`] and [`FontWidth`] come from [`fontique`](https://docs.rs/fontique).
//! [`FontStyle`] and [`FontWidth`] come from [`parley`](https://docs.rs/parley).

mod attrs;

Expand All @@ -15,8 +15,8 @@ use peniko::{
};

pub use attrs::{Attrs, AttrsList, AttrsOwned, FamilyOwned, LineHeightValue};
pub use fontique::{FontStyle, FontWeight, FontWidth};
pub use parley::layout::Glyph;
pub use parley::{FontStyle, FontWeight, FontWidth};

// --- Brush type for Parley ---

Expand Down
4 changes: 2 additions & 2 deletions src/style/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! CSS properties like borders and padding.

use floem_renderer::text::FontWeight;
use parley::style::{OverflowWrap, WordBreakStrength};
use parley::style::{OverflowWrap, WordBreak};
use peniko::color::palette;
use peniko::kurbo::Stroke;
use peniko::{Brush, Color};
Expand All @@ -29,7 +29,7 @@ pub enum TextOverflow {
NoWrap(NoWrapOverflow),
Wrap {
overflow_wrap: OverflowWrap,
word_break: WordBreakStrength,
word_break: WordBreak,
},
}

Expand Down
4 changes: 2 additions & 2 deletions src/style/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ use taffy::{
use crate::layout::responsive::{GridBreakpoints, ScreenSize, ScreenSizeBp};

use crate::style::components::Focus;
use crate::text::{OverflowWrap, WordBreakStrength};
use crate::text::{OverflowWrap, WordBreak};
use crate::views::editor::SelectionColor;
// Import macros from crate root (they are #[macro_export] in props.rs)
use crate::{prop, prop_extractor};
Expand Down Expand Up @@ -3447,7 +3447,7 @@ impl Style {
pub fn text_wrap(self) -> Self {
self.text_overflow(TextOverflow::Wrap {
overflow_wrap: OverflowWrap::Normal,
word_break: WordBreakStrength::Normal,
word_break: WordBreak::Normal,
})
}

Expand Down
27 changes: 15 additions & 12 deletions src/text/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{
use floem_renderer::Renderer as _;
use floem_renderer::text::{AttrsList, GlyphRunProps, TextBrush};
use parking_lot::Mutex;
use parley::swash::{FontRef, scale::ScaleContext, zeno};
use parley::{
Affinity, Alignment, Cursor, FontContext, LayoutContext, Selection,
layout::{AlignmentOptions, Layout},
Expand All @@ -19,6 +18,7 @@ use peniko::{
Fill, FontData,
kurbo::{Affine, Point, Size},
};
use swash::{FontRef, scale::ScaleContext, zeno};

use crate::paint::Renderer;

Expand Down Expand Up @@ -353,11 +353,8 @@ impl TextLayout {
};
self.layout.break_all_lines(max_advance);

if let Some(align) = self.alignment
&& let Some(width) = width
{
self.layout
.align(Some(width), align, AlignmentOptions::default());
if let Some(align) = self.alignment {
self.layout.align(align, AlignmentOptions::default());
}
}

Expand Down Expand Up @@ -538,9 +535,9 @@ impl TextLayout {
.get(mid)
.map_or(std::cmp::Ordering::Greater, |line| {
let metrics = line.metrics();
if cursor_y < metrics.min_coord {
if cursor_y < metrics.block_min_coord {
std::cmp::Ordering::Greater
} else if cursor_y >= metrics.max_coord {
} else if cursor_y >= metrics.block_max_coord {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
Expand Down Expand Up @@ -637,7 +634,8 @@ impl TextLayout {
/// This is the geometry helper to use for painted selection backgrounds.
///
/// Compared with [`selection_geometry_with`](Self::selection_geometry_with), this method:
/// - expands each rectangle vertically to the containing line's full `min_coord..max_coord`
/// - expands each rectangle vertically to the containing line's full
/// `block_min_coord..block_max_coord`
/// - expands horizontal bounds to the actual glyph outline bounds of the selected text
///
/// The vertical expansion is important for consistent full-line selection backgrounds.
Expand Down Expand Up @@ -718,7 +716,12 @@ impl TextLayout {
run_offset += run.advance() as f64;
}

f(min_x, m.min_coord as f64, max_x, m.max_coord as f64);
f(
min_x,
m.block_min_coord as f64,
max_x,
m.block_max_coord as f64,
);
} else {
f(bbox.x0, bbox.y0, bbox.x1, bbox.y1);
}
Expand Down Expand Up @@ -752,8 +755,8 @@ impl TextLayout {
for i in 0..self.layout.len() {
if let Some(line) = self.layout.get(i) {
let m = line.metrics();
min_y = min_y.min(m.min_coord);
max_y = max_y.max(m.max_coord);
min_y = min_y.min(m.block_min_coord);
max_y = max_y.max(m.block_max_coord);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use layout::{FONT_CONTEXT, TextLayout, TextSelection};
pub use layout_state::{TextLayoutState, TextOverflowChanged};
pub use parley::Alignment;
pub use parley::layout::{Affinity, Cursor, Selection};
pub use parley::style::{OverflowWrap, TextWrapMode, WordBreakStrength};
pub use parley::style::{OverflowWrap, TextWrapMode, WordBreak};

/// Returns the byte ranges of the source text's logical paragraphs.
///
Expand Down
4 changes: 2 additions & 2 deletions src/views/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
style_class,
text::{
Attrs, AttrsList, Cursor, FamilyOwned, TextLayout, TextLayoutState, TextSelection,
WordBreakStrength,
WordBreak,
},
view::{LayoutNodeCx, View},
views::editor::SelectionColor,
Expand Down Expand Up @@ -238,7 +238,7 @@ impl Label {
}
attrs = attrs.line_height(self.label_props.line_height());
if let TextOverflow::Wrap { word_break, .. } = self.label_props.text_overflow()
&& word_break != WordBreakStrength::Normal
&& word_break != WordBreak::Normal
{
attrs = attrs.word_break(word_break);
}
Expand Down
Loading