motion_content/text/
paragraph.rs1use super::*;
4use crate::vector::CompileCache;
5
6pub(crate) type SharedLayouts = Arc<Mutex<BTreeMap<ParagraphSpec, Arc<ParagraphLayout>>>>;
7
8#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub(crate) struct SpanSpec {
11 pub(super) text: Arc<str>,
12 pub(super) family: Option<Arc<str>>,
13 pub(super) size: Option<u64>,
14 pub(super) weight: Option<u16>,
15 pub(super) italic: bool,
16}
17
18impl From<&TextSpan> for SpanSpec {
19 fn from(span: &TextSpan) -> Self {
20 Self {
21 text: span.text.clone(),
22 family: span.family.clone(),
23 size: span.size.map(f64::to_bits),
24 weight: span.weight.map(|weight| weight.0),
25 italic: span.italic,
26 }
27 }
28}
29
30#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub(crate) struct ParagraphSpec {
33 pub(super) spans: Vec<SpanSpec>,
34 pub(super) family: Arc<str>,
35 pub(super) size: u64,
36 pub(super) weight: u16,
37 pub(super) line_height: u64,
38 pub(super) spacing: u64,
39 pub(super) width: Option<u64>,
40 pub(super) alignment: TextAlignment,
41}
42
43#[derive(Clone, Debug)]
49pub struct ParagraphStyle {
50 pub(super) cache: CompileCache<ParagraphSpec, Result<Arc<ParagraphLayout>, ValidationError>>,
51 pub(super) fills: Arc<[Option<Paint>]>,
52 pub(super) fonts: Option<FontLibrary>,
53}
54
55impl ParagraphStyle {
56 pub fn new(text: impl Into<Arc<str>>) -> Self {
58 Self::rich([TextSpan::new(text)])
59 }
60
61 pub fn rich(spans: impl IntoIterator<Item = TextSpan>) -> Self {
63 let spans = spans.into_iter().take(257).collect::<Vec<_>>();
64 Self {
65 fills: spans.iter().map(|span| span.fill.clone()).collect(),
66 cache: CompileCache::new(ParagraphSpec {
67 spans: spans.iter().map(SpanSpec::from).collect(),
68 family: "".into(),
69 size: 24.0f64.to_bits(),
70 weight: FontWeight::NORMAL.0,
71 line_height: 1.3f64.to_bits(),
72 spacing: 0.0f64.to_bits(),
73 width: None,
74 alignment: TextAlignment::Start,
75 }),
76 fonts: None,
77 }
78 }
79
80 pub(super) fn spec(&self) -> &ParagraphSpec {
81 self.cache.key()
82 }
83
84 pub(super) fn with_spans(&self, spans: Vec<SpanSpec>, fills: Vec<Option<Paint>>) -> Self {
85 Self {
86 cache: self.cache.map_key(|spec| spec.spans = spans),
87 fills: fills.into(),
88 fonts: self.fonts.clone(),
89 }
90 }
91
92 fn rekey(mut self, change: impl FnOnce(&mut ParagraphSpec)) -> Self {
93 self.cache = self.cache.map_key(change);
94 self
95 }
96
97 pub fn family(self, family: impl Into<Arc<str>>) -> Self {
99 let family = family.into();
100 self.rekey(|spec| spec.family = family)
101 }
102
103 pub fn size(self, size: f64) -> Self {
105 self.rekey(|spec| spec.size = size.to_bits())
106 }
107
108 pub fn weight(self, weight: FontWeight) -> Self {
110 self.rekey(|spec| spec.weight = weight.0)
111 }
112
113 pub fn line_height(self, height: f64) -> Self {
115 self.rekey(|spec| spec.line_height = height.to_bits())
116 }
117
118 pub fn letter_spacing(self, spacing: f64) -> Self {
120 self.rekey(|spec| spec.spacing = spacing.to_bits())
121 }
122
123 pub fn max_width(self, width: f64) -> Self {
125 self.rekey(|spec| spec.width = Some(width.to_bits()))
126 }
127
128 pub fn alignment(self, alignment: TextAlignment) -> Self {
130 self.rekey(|spec| spec.alignment = alignment)
131 }
132
133 pub fn fonts(mut self, fonts: &FontLibrary) -> Self {
135 self.fonts = Some(fonts.clone());
136 self
137 }
138}