1use std::sync::Arc;
6
7use strict_num::NonZeroPositiveF32;
8pub use svgtypes::FontFamily;
9
10#[cfg(feature = "text")]
11use crate::layout::Span;
12use crate::{Fill, Group, NonEmptyString, PaintOrder, Rect, Stroke, TextRendering, Transform};
13
14#[allow(missing_docs)]
16#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
17pub enum FontStretch {
18 UltraCondensed,
19 ExtraCondensed,
20 Condensed,
21 SemiCondensed,
22 Normal,
23 SemiExpanded,
24 Expanded,
25 ExtraExpanded,
26 UltraExpanded,
27}
28
29impl Default for FontStretch {
30 #[inline]
31 fn default() -> Self {
32 Self::Normal
33 }
34}
35
36#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
38pub enum FontStyle {
39 Normal,
41 Italic,
43 Oblique,
45}
46
47impl Default for FontStyle {
48 #[inline]
49 fn default() -> FontStyle {
50 Self::Normal
51 }
52}
53
54#[derive(Clone, Eq, PartialEq, Hash, Debug)]
56pub struct Font {
57 pub(crate) families: Vec<FontFamily>,
58 pub(crate) style: FontStyle,
59 pub(crate) stretch: FontStretch,
60 pub(crate) weight: u16,
61}
62
63impl Font {
64 pub fn families(&self) -> &[FontFamily] {
68 &self.families
69 }
70
71 pub fn style(&self) -> FontStyle {
73 self.style
74 }
75
76 pub fn stretch(&self) -> FontStretch {
78 self.stretch
79 }
80
81 pub fn weight(&self) -> u16 {
83 self.weight
84 }
85}
86
87#[allow(missing_docs)]
89#[derive(Clone, Copy, PartialEq, Debug)]
90pub enum DominantBaseline {
91 Auto,
92 UseScript,
93 NoChange,
94 ResetSize,
95 Ideographic,
96 Alphabetic,
97 Hanging,
98 Mathematical,
99 Central,
100 Middle,
101 TextAfterEdge,
102 TextBeforeEdge,
103}
104
105impl Default for DominantBaseline {
106 fn default() -> Self {
107 Self::Auto
108 }
109}
110
111#[allow(missing_docs)]
113#[derive(Clone, Copy, PartialEq, Debug)]
114pub enum AlignmentBaseline {
115 Auto,
116 Baseline,
117 BeforeEdge,
118 TextBeforeEdge,
119 Middle,
120 Central,
121 AfterEdge,
122 TextAfterEdge,
123 Ideographic,
124 Alphabetic,
125 Hanging,
126 Mathematical,
127}
128
129impl Default for AlignmentBaseline {
130 fn default() -> Self {
131 Self::Auto
132 }
133}
134
135#[allow(missing_docs)]
137#[derive(Clone, Copy, PartialEq, Debug)]
138pub enum BaselineShift {
139 Baseline,
140 Subscript,
141 Superscript,
142 Number(f32),
143}
144
145impl Default for BaselineShift {
146 #[inline]
147 fn default() -> BaselineShift {
148 BaselineShift::Baseline
149 }
150}
151
152#[allow(missing_docs)]
154#[derive(Clone, Copy, PartialEq, Debug)]
155pub enum LengthAdjust {
156 Spacing,
157 SpacingAndGlyphs,
158}
159
160impl Default for LengthAdjust {
161 fn default() -> Self {
162 Self::Spacing
163 }
164}
165
166#[derive(Clone, Debug)]
173pub struct TextDecorationStyle {
174 pub(crate) fill: Option<Fill>,
175 pub(crate) stroke: Option<Stroke>,
176}
177
178impl TextDecorationStyle {
179 pub fn fill(&self) -> Option<&Fill> {
181 self.fill.as_ref()
182 }
183
184 pub fn stroke(&self) -> Option<&Stroke> {
186 self.stroke.as_ref()
187 }
188}
189
190#[derive(Clone, Debug)]
192pub struct TextDecoration {
193 pub(crate) underline: Option<TextDecorationStyle>,
194 pub(crate) overline: Option<TextDecorationStyle>,
195 pub(crate) line_through: Option<TextDecorationStyle>,
196}
197
198impl TextDecoration {
199 pub fn underline(&self) -> Option<&TextDecorationStyle> {
201 self.underline.as_ref()
202 }
203
204 pub fn overline(&self) -> Option<&TextDecorationStyle> {
206 self.overline.as_ref()
207 }
208
209 pub fn line_through(&self) -> Option<&TextDecorationStyle> {
211 self.line_through.as_ref()
212 }
213}
214
215#[derive(Clone, Debug)]
219pub struct TextSpan {
220 pub(crate) start: usize,
221 pub(crate) end: usize,
222 pub(crate) fill: Option<Fill>,
223 pub(crate) stroke: Option<Stroke>,
224 pub(crate) paint_order: PaintOrder,
225 pub(crate) font: Font,
226 pub(crate) font_size: NonZeroPositiveF32,
227 pub(crate) small_caps: bool,
228 pub(crate) apply_kerning: bool,
229 pub(crate) decoration: TextDecoration,
230 pub(crate) dominant_baseline: DominantBaseline,
231 pub(crate) alignment_baseline: AlignmentBaseline,
232 pub(crate) baseline_shift: Vec<BaselineShift>,
233 pub(crate) visible: bool,
234 pub(crate) letter_spacing: f32,
235 pub(crate) word_spacing: f32,
236 pub(crate) text_length: Option<f32>,
237 pub(crate) length_adjust: LengthAdjust,
238}
239
240impl TextSpan {
241 pub fn start(&self) -> usize {
245 self.start
246 }
247
248 pub fn end(&self) -> usize {
252 self.end
253 }
254
255 pub fn fill(&self) -> Option<&Fill> {
257 self.fill.as_ref()
258 }
259
260 pub fn stroke(&self) -> Option<&Stroke> {
262 self.stroke.as_ref()
263 }
264
265 pub fn paint_order(&self) -> PaintOrder {
267 self.paint_order
268 }
269
270 pub fn font(&self) -> &Font {
272 &self.font
273 }
274
275 pub fn font_size(&self) -> NonZeroPositiveF32 {
277 self.font_size
278 }
279
280 pub fn small_caps(&self) -> bool {
284 self.small_caps
285 }
286
287 pub fn apply_kerning(&self) -> bool {
291 self.apply_kerning
292 }
293
294 pub fn decoration(&self) -> &TextDecoration {
296 &self.decoration
297 }
298
299 pub fn dominant_baseline(&self) -> DominantBaseline {
301 self.dominant_baseline
302 }
303
304 pub fn alignment_baseline(&self) -> AlignmentBaseline {
306 self.alignment_baseline
307 }
308
309 pub fn baseline_shift(&self) -> &[BaselineShift] {
313 &self.baseline_shift
314 }
315
316 pub fn is_visible(&self) -> bool {
318 self.visible
319 }
320
321 pub fn letter_spacing(&self) -> f32 {
323 self.letter_spacing
324 }
325
326 pub fn word_spacing(&self) -> f32 {
328 self.word_spacing
329 }
330
331 pub fn text_length(&self) -> Option<f32> {
333 self.text_length
334 }
335
336 pub fn length_adjust(&self) -> LengthAdjust {
338 self.length_adjust
339 }
340}
341
342#[allow(missing_docs)]
344#[derive(Clone, Copy, PartialEq, Debug)]
345pub enum TextAnchor {
346 Start,
347 Middle,
348 End,
349}
350
351impl Default for TextAnchor {
352 fn default() -> Self {
353 Self::Start
354 }
355}
356
357#[derive(Debug)]
359pub struct TextPath {
360 pub(crate) id: NonEmptyString,
361 pub(crate) start_offset: f32,
362 pub(crate) path: Arc<tiny_skia_path::Path>,
363}
364
365impl TextPath {
366 pub fn id(&self) -> &str {
370 self.id.get()
371 }
372
373 pub fn start_offset(&self) -> f32 {
377 self.start_offset
378 }
379
380 pub fn path(&self) -> &tiny_skia_path::Path {
382 &self.path
383 }
384}
385
386#[derive(Clone, Debug)]
388pub enum TextFlow {
389 Linear,
393 Path(Arc<TextPath>),
395}
396
397#[derive(Clone, Debug)]
401pub struct TextChunk {
402 pub(crate) x: Option<f32>,
403 pub(crate) y: Option<f32>,
404 pub(crate) anchor: TextAnchor,
405 pub(crate) spans: Vec<TextSpan>,
406 pub(crate) text_flow: TextFlow,
407 pub(crate) text: String,
408}
409
410impl TextChunk {
411 pub fn x(&self) -> Option<f32> {
413 self.x
414 }
415
416 pub fn y(&self) -> Option<f32> {
418 self.y
419 }
420
421 pub fn anchor(&self) -> TextAnchor {
423 self.anchor
424 }
425
426 pub fn spans(&self) -> &[TextSpan] {
428 &self.spans
429 }
430
431 pub fn text_flow(&self) -> TextFlow {
433 self.text_flow.clone()
434 }
435
436 pub fn text(&self) -> &str {
438 &self.text
439 }
440}
441
442#[allow(missing_docs)]
444#[derive(Clone, Copy, PartialEq, Debug)]
445pub enum WritingMode {
446 LeftToRight,
447 TopToBottom,
448}
449
450#[derive(Clone, Debug)]
454pub struct Text {
455 pub(crate) id: String,
456 pub(crate) rendering_mode: TextRendering,
457 pub(crate) dx: Vec<f32>,
458 pub(crate) dy: Vec<f32>,
459 pub(crate) rotate: Vec<f32>,
460 pub(crate) writing_mode: WritingMode,
461 pub(crate) chunks: Vec<TextChunk>,
462 pub(crate) abs_transform: Transform,
463 pub(crate) bounding_box: Rect,
464 pub(crate) abs_bounding_box: Rect,
465 pub(crate) stroke_bounding_box: Rect,
466 pub(crate) abs_stroke_bounding_box: Rect,
467 pub(crate) flattened: Box<Group>,
468 #[cfg(feature = "text")]
469 pub(crate) layouted: Vec<Span>,
470}
471
472impl Text {
473 pub fn id(&self) -> &str {
479 &self.id
480 }
481
482 pub fn rendering_mode(&self) -> TextRendering {
486 self.rendering_mode
487 }
488
489 pub fn dx(&self) -> &[f32] {
493 &self.dx
494 }
495
496 pub fn dy(&self) -> &[f32] {
500 &self.dy
501 }
502
503 pub fn rotate(&self) -> &[f32] {
507 &self.rotate
508 }
509
510 pub fn writing_mode(&self) -> WritingMode {
512 self.writing_mode
513 }
514
515 pub fn chunks(&self) -> &[TextChunk] {
517 &self.chunks
518 }
519
520 pub fn abs_transform(&self) -> Transform {
527 self.abs_transform
528 }
529
530 pub fn bounding_box(&self) -> Rect {
542 self.bounding_box
543 }
544
545 pub fn abs_bounding_box(&self) -> Rect {
549 self.abs_bounding_box
550 }
551
552 pub fn stroke_bounding_box(&self) -> Rect {
558 self.stroke_bounding_box
559 }
560
561 pub fn abs_stroke_bounding_box(&self) -> Rect {
563 self.abs_stroke_bounding_box
564 }
565
566 pub fn flattened(&self) -> &Group {
583 &self.flattened
584 }
585
586 #[cfg(feature = "text")]
592 pub fn layouted(&self) -> &[Span] {
593 &self.layouted
594 }
595
596 pub(crate) fn subroots(&self, f: &mut dyn FnMut(&Group)) {
597 f(&self.flattened);
598 }
599}