Skip to content

Commit f0b546a

Browse files
committed
Move things into i_slint_core::textlayout::sharedparley
1 parent 2405d41 commit f0b546a

File tree

9 files changed

+161
-172
lines changed

9 files changed

+161
-172
lines changed

internal/common/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ path = "lib.rs"
1818

1919
[features]
2020
default = []
21-
shared-fontique = ["dep:fontique", "dep:ttf-parser", "dep:parley"]
21+
shared-fontique = ["dep:fontique", "dep:ttf-parser"]
2222

2323
[dependencies]
2424
ttf-parser = { workspace = true, optional = true }
2525
fontique = { workspace = true, optional = true }
26-
parley = { version = "0.5.0", optional = true }
2726

2827
[package.metadata.docs.rs]
2928
rustdoc-args = ["--generate-link-to-definition"]

internal/common/sharedfontique.rs

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

44
pub use fontique;
5-
pub use parley;
65
pub use ttf_parser;
76

87
use std::collections::HashMap;
98
use std::sync::Arc;
109

11-
static COLLECTION: std::sync::LazyLock<Collection> = std::sync::LazyLock::new(|| {
10+
pub static COLLECTION: std::sync::LazyLock<Collection> = std::sync::LazyLock::new(|| {
1211
let mut collection = fontique::Collection::new(fontique::CollectionOptions {
1312
shared: true,
1413
..Default::default()
@@ -54,38 +53,10 @@ pub fn get_collection() -> Collection {
5453
COLLECTION.clone()
5554
}
5655

57-
pub fn font_context() -> parley::FontContext {
58-
parley::FontContext {
59-
collection: COLLECTION.inner.clone(),
60-
source_cache: COLLECTION.source_cache.clone(),
61-
}
62-
}
63-
64-
#[derive(Debug, PartialEq, Clone, Copy)]
65-
pub enum BrushTextStrokeStyle {
66-
/// The inside edge of the stroke is at the outer edge of the text.
67-
Outside,
68-
/// The center line of the stroke is at the outer edge of the text, like in Adobe Illustrator.
69-
Center,
70-
}
71-
72-
#[derive(Debug, Default, PartialEq, Clone, Copy)]
73-
pub struct Brush {
74-
pub is_selected: bool,
75-
pub stroke: Option<BrushTextStrokeStyle>,
76-
}
77-
78-
static LAYOUT_CONTEXT: std::sync::LazyLock<parley::LayoutContext<Brush>> =
79-
std::sync::LazyLock::new(|| Default::default());
80-
81-
pub fn layout_context() -> parley::LayoutContext<Brush> {
82-
LAYOUT_CONTEXT.clone()
83-
}
84-
8556
#[derive(Clone)]
8657
pub struct Collection {
87-
inner: fontique::Collection,
88-
source_cache: fontique::SourceCache,
58+
pub inner: fontique::Collection,
59+
pub source_cache: fontique::SourceCache,
8960
pub default_fonts: Arc<HashMap<std::path::PathBuf, fontique::QueryFont>>,
9061
}
9162

internal/core/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ unstable-wgpu-26 = ["dep:wgpu-26"]
6767

6868
default = ["std", "unicode"]
6969

70+
shared-parley = ["shared-fontique", "dep:parley"]
71+
7072
[dependencies]
7173
i-slint-common = { workspace = true, features = ["default"] }
7274
i-slint-core-macros = { workspace = true, features = ["default"] }
@@ -100,6 +102,7 @@ unicode-script = { version = "0.5.7", optional = true }
100102
integer-sqrt = { version = "0.1.5" }
101103
bytemuck = { workspace = true, optional = true, features = ["derive"] }
102104
sys-locale = { version = "0.3.2", optional = true }
105+
parley = { version = "0.5.0", optional = true }
103106

104107
image = { workspace = true, optional = true, default-features = false }
105108
clru = { workspace = true, optional = true }

internal/core/textlayout.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ use linebreak_simple::{BreakOpportunity, LineBreakIterator};
4040
mod fragments;
4141
mod glyphclusters;
4242
mod shaping;
43+
#[cfg(feature = "shared-parley")]
44+
pub mod sharedparley;
4345
use shaping::ShapeBuffer;
4446
pub use shaping::{AbstractFont, FontMetrics, Glyph, TextShaper};
4547

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
pub use parley;
2+
3+
use crate::{
4+
graphics::FontRequest,
5+
items::TextStrokeStyle,
6+
lengths::LogicalLength,
7+
textlayout::{TextHorizontalAlignment, TextVerticalAlignment, TextWrap},
8+
};
9+
use i_slint_common::sharedfontique;
10+
11+
pub const DEFAULT_FONT_SIZE: LogicalLength = LogicalLength::new(12.);
12+
13+
fn font_context() -> parley::FontContext {
14+
parley::FontContext {
15+
collection: sharedfontique::COLLECTION.inner.clone(),
16+
source_cache: sharedfontique::COLLECTION.source_cache.clone(),
17+
}
18+
}
19+
20+
static LAYOUT_CONTEXT: std::sync::LazyLock<parley::LayoutContext<Brush>> =
21+
std::sync::LazyLock::new(|| Default::default());
22+
23+
#[derive(Debug, Default, PartialEq, Clone, Copy)]
24+
pub struct Brush {
25+
pub is_selected: bool,
26+
pub stroke: Option<TextStrokeStyle>,
27+
}
28+
29+
pub struct LayoutOptions {
30+
pub max_width: Option<LogicalLength>,
31+
pub max_height: Option<LogicalLength>,
32+
pub horizontal_align: TextHorizontalAlignment,
33+
pub vertical_align: TextVerticalAlignment,
34+
pub stroke: Option<TextStrokeStyle>,
35+
pub selection: Option<std::ops::Range<usize>>,
36+
pub font_request: Option<FontRequest>,
37+
pub text_wrap: TextWrap,
38+
}
39+
40+
impl Default for LayoutOptions {
41+
fn default() -> Self {
42+
Self {
43+
max_width: None,
44+
max_height: None,
45+
horizontal_align: TextHorizontalAlignment::Left,
46+
vertical_align: TextVerticalAlignment::Top,
47+
stroke: None,
48+
selection: None,
49+
font_request: None,
50+
text_wrap: TextWrap::WordWrap,
51+
}
52+
}
53+
}
54+
55+
pub fn layout(text: &str, scale_factor: f32, options: LayoutOptions) -> Layout {
56+
let mut font_context = font_context();
57+
let mut layout_context = LAYOUT_CONTEXT.clone();
58+
59+
let mut builder = layout_context.ranged_builder(&mut font_context, text, scale_factor, true);
60+
if let Some(ref font_request) = options.font_request {
61+
if let Some(family) = &font_request.family {
62+
builder.push_default(parley::StyleProperty::FontStack(
63+
parley::style::FontStack::Single(parley::style::FontFamily::Named(
64+
family.as_str().into(),
65+
)),
66+
));
67+
}
68+
if let Some(weight) = font_request.weight {
69+
builder.push_default(parley::StyleProperty::FontWeight(
70+
parley::style::FontWeight::new(weight as f32),
71+
));
72+
}
73+
if let Some(letter_spacing) = font_request.letter_spacing {
74+
builder.push_default(parley::StyleProperty::LetterSpacing(letter_spacing.get()));
75+
}
76+
builder.push_default(parley::StyleProperty::FontStyle(if font_request.italic {
77+
parley::style::FontStyle::Italic
78+
} else {
79+
parley::style::FontStyle::Normal
80+
}));
81+
}
82+
let pixel_size = options
83+
.font_request
84+
.and_then(|font_request| font_request.pixel_size)
85+
.unwrap_or(DEFAULT_FONT_SIZE);
86+
builder.push_default(parley::StyleProperty::FontSize(pixel_size.get()));
87+
builder.push_default(parley::StyleProperty::WordBreak(match options.text_wrap {
88+
TextWrap::NoWrap => parley::style::WordBreakStrength::KeepAll,
89+
TextWrap::WordWrap => parley::style::WordBreakStrength::Normal,
90+
TextWrap::CharWrap => parley::style::WordBreakStrength::BreakAll,
91+
}));
92+
93+
builder.push_default(parley::StyleProperty::Brush(Brush {
94+
stroke: options.stroke,
95+
..Default::default()
96+
}));
97+
if let Some(selection) = options.selection {
98+
builder.push(
99+
parley::StyleProperty::Brush(Brush { stroke: options.stroke, is_selected: true }),
100+
selection,
101+
);
102+
}
103+
104+
let mut layout: parley::Layout<Brush> = builder.build(text);
105+
layout.break_all_lines(options.max_width.map(|max_width| max_width.get()));
106+
layout.align(
107+
options.max_width.map(|max_width| max_width.get()),
108+
match options.horizontal_align {
109+
TextHorizontalAlignment::Left => parley::Alignment::Left,
110+
TextHorizontalAlignment::Center => parley::Alignment::Middle,
111+
TextHorizontalAlignment::Right => parley::Alignment::Right,
112+
},
113+
parley::AlignmentOptions::default(),
114+
);
115+
116+
let y_offset = match (options.max_height, options.vertical_align) {
117+
(Some(max_height), TextVerticalAlignment::Center) => {
118+
(max_height.get() - layout.height()) / 2.0
119+
}
120+
(Some(max_height), TextVerticalAlignment::Bottom) => max_height.get() - layout.height(),
121+
(None, _) | (Some(_), TextVerticalAlignment::Top) => 0.0,
122+
};
123+
124+
Layout { inner: layout, y_offset }
125+
}
126+
127+
pub struct Layout {
128+
pub inner: parley::Layout<Brush>,
129+
pub y_offset: f32,
130+
}

internal/renderers/femtovg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ wgpu-26 = ["dep:wgpu-26", "femtovg/wgpu", "i-slint-core/unstable-wgpu-26"]
2323
unstable-wgpu-26 = ["wgpu-26"]
2424

2525
[dependencies]
26-
i-slint-core = { workspace = true, features = ["default", "box-shadow-cache", "shared-fontique"] }
26+
i-slint-core = { workspace = true, features = ["default", "box-shadow-cache", "shared-fontique", "shared-parley"] }
2727
i-slint-core-macros = { workspace = true, features = ["default"] }
2828
i-slint-common = { workspace = true, features = ["default", "shared-fontique"] }
2929

internal/renderers/femtovg/fonts.rs

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,12 @@
33

44
// cspell:ignore Noto fontconfig
55

6-
use crate::PhysicalLength;
76
use core::num::NonZeroUsize;
87
use femtovg::TextContext;
9-
use i_slint_common::sharedfontique::{self, parley};
10-
use i_slint_core::{
11-
graphics::FontRequest,
12-
items::{TextHorizontalAlignment, TextVerticalAlignment, TextWrap},
13-
lengths::LogicalLength,
14-
};
8+
use i_slint_core::textlayout::sharedparley::parley;
159
use std::cell::RefCell;
1610
use std::collections::HashMap;
1711

18-
pub const DEFAULT_FONT_SIZE: LogicalLength = LogicalLength::new(12.);
19-
2012
pub struct FontCache {
2113
pub(crate) text_context: femtovg::TextContext,
2214
fonts: HashMap<(u64, u32), femtovg::FontId>,
@@ -45,109 +37,3 @@ impl FontCache {
4537
thread_local! {
4638
pub static FONT_CACHE: RefCell<FontCache> = RefCell::new(Default::default())
4739
}
48-
49-
pub struct LayoutOptions {
50-
pub max_width: Option<LogicalLength>,
51-
pub max_height: Option<LogicalLength>,
52-
pub horizontal_align: TextHorizontalAlignment,
53-
pub vertical_align: TextVerticalAlignment,
54-
pub stroke: Option<sharedfontique::BrushTextStrokeStyle>,
55-
pub selection: Option<std::ops::Range<usize>>,
56-
pub font_request: Option<FontRequest>,
57-
pub text_wrap: TextWrap,
58-
}
59-
60-
impl Default for LayoutOptions {
61-
fn default() -> Self {
62-
Self {
63-
max_width: None,
64-
max_height: None,
65-
horizontal_align: TextHorizontalAlignment::Left,
66-
vertical_align: TextVerticalAlignment::Top,
67-
stroke: None,
68-
selection: None,
69-
font_request: None,
70-
text_wrap: TextWrap::WordWrap,
71-
}
72-
}
73-
}
74-
75-
pub fn layout(text: &str, scale_factor: f32, options: LayoutOptions) -> Layout {
76-
let mut font_context = sharedfontique::font_context();
77-
let mut layout_context = sharedfontique::layout_context();
78-
79-
let mut builder = layout_context.ranged_builder(&mut font_context, text, scale_factor, true);
80-
if let Some(ref font_request) = options.font_request {
81-
if let Some(family) = &font_request.family {
82-
builder.push_default(parley::StyleProperty::FontStack(
83-
parley::style::FontStack::Single(parley::style::FontFamily::Named(
84-
family.as_str().into(),
85-
)),
86-
));
87-
}
88-
if let Some(weight) = font_request.weight {
89-
builder.push_default(parley::StyleProperty::FontWeight(
90-
parley::style::FontWeight::new(weight as f32),
91-
));
92-
}
93-
if let Some(letter_spacing) = font_request.letter_spacing {
94-
builder.push_default(parley::StyleProperty::LetterSpacing(letter_spacing.get()));
95-
}
96-
builder.push_default(parley::StyleProperty::FontStyle(if font_request.italic {
97-
parley::style::FontStyle::Italic
98-
} else {
99-
parley::style::FontStyle::Normal
100-
}));
101-
}
102-
let pixel_size = options
103-
.font_request
104-
.and_then(|font_request| font_request.pixel_size)
105-
.unwrap_or(DEFAULT_FONT_SIZE);
106-
builder.push_default(parley::StyleProperty::FontSize(pixel_size.get()));
107-
builder.push_default(parley::StyleProperty::WordBreak(match options.text_wrap {
108-
TextWrap::NoWrap => parley::style::WordBreakStrength::KeepAll,
109-
TextWrap::WordWrap => parley::style::WordBreakStrength::Normal,
110-
TextWrap::CharWrap => parley::style::WordBreakStrength::BreakAll,
111-
}));
112-
113-
builder.push_default(parley::StyleProperty::Brush(sharedfontique::Brush {
114-
stroke: options.stroke,
115-
..Default::default()
116-
}));
117-
if let Some(selection) = options.selection {
118-
builder.push(
119-
parley::StyleProperty::Brush(sharedfontique::Brush {
120-
stroke: options.stroke,
121-
is_selected: true,
122-
}),
123-
selection,
124-
);
125-
}
126-
127-
let mut layout: parley::Layout<sharedfontique::Brush> = builder.build(text);
128-
layout.break_all_lines(options.max_width.map(|max_width| max_width.get()));
129-
layout.align(
130-
options.max_width.map(|max_width| max_width.get()),
131-
match options.horizontal_align {
132-
TextHorizontalAlignment::Left => parley::Alignment::Left,
133-
TextHorizontalAlignment::Center => parley::Alignment::Middle,
134-
TextHorizontalAlignment::Right => parley::Alignment::Right,
135-
},
136-
parley::AlignmentOptions::default(),
137-
);
138-
139-
let y_offset = match (options.max_height, options.vertical_align) {
140-
(Some(max_height), TextVerticalAlignment::Center) => {
141-
(max_height.get() - layout.height()) / 2.0
142-
}
143-
(Some(max_height), TextVerticalAlignment::Bottom) => max_height.get() - layout.height(),
144-
(None, _) | (Some(_), TextVerticalAlignment::Top) => 0.0,
145-
};
146-
147-
Layout { inner: layout, y_offset }
148-
}
149-
150-
pub struct Layout {
151-
pub inner: parley::Layout<sharedfontique::Brush>,
152-
pub y_offset: f32,
153-
}

0 commit comments

Comments
 (0)