1#![allow(missing_docs)]
5
6use std::sync::Arc;
7
8use strict_num::NonZeroPositiveF32;
9pub use svgtypes::FontFamily;
10
11#[cfg(feature = "text")]
12use crate::layout::Span;
13use crate::{Fill, Group, NonEmptyString, PaintOrder, Rect, Stroke, TextRendering, Transform};
14
15#[allow(missing_docs)]
17#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
18pub enum FontStretch {
19 UltraCondensed,
20 ExtraCondensed,
21 Condensed,
22 SemiCondensed,
23 Normal,
24 SemiExpanded,
25 Expanded,
26 ExtraExpanded,
27 UltraExpanded,
28}
29
30impl Default for FontStretch {
31 #[inline]
32 fn default() -> Self {
33 Self::Normal
34 }
35}
36
37#[cfg(feature = "text")]
38impl From<fontdb::Stretch> for FontStretch {
39 fn from(stretch: fontdb::Stretch) -> Self {
40 match stretch {
41 fontdb::Stretch::UltraCondensed => FontStretch::UltraCondensed,
42 fontdb::Stretch::ExtraCondensed => FontStretch::ExtraCondensed,
43 fontdb::Stretch::Condensed => FontStretch::Condensed,
44 fontdb::Stretch::SemiCondensed => FontStretch::SemiCondensed,
45 fontdb::Stretch::Normal => FontStretch::Normal,
46 fontdb::Stretch::SemiExpanded => FontStretch::SemiExpanded,
47 fontdb::Stretch::Expanded => FontStretch::Expanded,
48 fontdb::Stretch::ExtraExpanded => FontStretch::ExtraExpanded,
49 fontdb::Stretch::UltraExpanded => FontStretch::UltraExpanded,
50 }
51 }
52}
53
54#[cfg(feature = "text")]
55impl From<FontStretch> for fontdb::Stretch {
56 fn from(stretch: FontStretch) -> Self {
57 match stretch {
58 FontStretch::UltraCondensed => fontdb::Stretch::UltraCondensed,
59 FontStretch::ExtraCondensed => fontdb::Stretch::ExtraCondensed,
60 FontStretch::Condensed => fontdb::Stretch::Condensed,
61 FontStretch::SemiCondensed => fontdb::Stretch::SemiCondensed,
62 FontStretch::Normal => fontdb::Stretch::Normal,
63 FontStretch::SemiExpanded => fontdb::Stretch::SemiExpanded,
64 FontStretch::Expanded => fontdb::Stretch::Expanded,
65 FontStretch::ExtraExpanded => fontdb::Stretch::ExtraExpanded,
66 FontStretch::UltraExpanded => fontdb::Stretch::UltraExpanded,
67 }
68 }
69}
70
71#[derive(Clone, Copy, Debug)]
75pub struct FontVariation {
76 pub tag: [u8; 4],
78 pub value: f32,
80}
81
82impl FontVariation {
83 pub fn new(tag: [u8; 4], value: f32) -> Self {
85 Self { tag, value }
86 }
87}
88
89impl PartialEq for FontVariation {
90 fn eq(&self, other: &Self) -> bool {
91 self.tag == other.tag && self.value.to_bits() == other.value.to_bits()
92 }
93}
94
95impl Eq for FontVariation {}
96
97impl std::hash::Hash for FontVariation {
98 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
99 self.tag.hash(state);
100 self.value.to_bits().hash(state);
101 }
102}
103
104#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
106pub enum FontStyle {
107 Normal,
109 Italic,
111 Oblique,
113}
114
115impl Default for FontStyle {
116 #[inline]
117 fn default() -> FontStyle {
118 Self::Normal
119 }
120}
121
122#[cfg(feature = "text")]
123impl From<fontdb::Style> for FontStyle {
124 fn from(style: fontdb::Style) -> Self {
125 match style {
126 fontdb::Style::Normal => FontStyle::Normal,
127 fontdb::Style::Italic => FontStyle::Italic,
128 fontdb::Style::Oblique => FontStyle::Oblique,
129 }
130 }
131}
132
133#[cfg(feature = "text")]
134impl From<FontStyle> for fontdb::Style {
135 fn from(style: FontStyle) -> Self {
136 match style {
137 FontStyle::Normal => fontdb::Style::Normal,
138 FontStyle::Italic => fontdb::Style::Italic,
139 FontStyle::Oblique => fontdb::Style::Oblique,
140 }
141 }
142}
143
144#[derive(Clone, Eq, PartialEq, Hash, Debug)]
146pub struct Font {
147 pub families: Vec<FontFamily>,
148 pub style: FontStyle,
149 pub stretch: FontStretch,
150 pub weight: u16,
151 pub variations: Vec<FontVariation>,
152}
153
154impl Font {
155 pub fn families(&self) -> &[FontFamily] {
159 &self.families
160 }
161
162 pub fn style(&self) -> FontStyle {
164 self.style
165 }
166
167 pub fn stretch(&self) -> FontStretch {
169 self.stretch
170 }
171
172 pub fn weight(&self) -> u16 {
174 self.weight
175 }
176
177 pub fn variations(&self) -> &[FontVariation] {
179 &self.variations
180 }
181}
182
183#[allow(missing_docs)]
185#[derive(Clone, Copy, PartialEq, Debug)]
186pub enum DominantBaseline {
187 Auto,
188 UseScript,
189 NoChange,
190 ResetSize,
191 Ideographic,
192 Alphabetic,
193 Hanging,
194 Mathematical,
195 Central,
196 Middle,
197 TextAfterEdge,
198 TextBeforeEdge,
199}
200
201impl Default for DominantBaseline {
202 fn default() -> Self {
203 Self::Auto
204 }
205}
206
207#[allow(missing_docs)]
209#[derive(Clone, Copy, PartialEq, Debug)]
210pub enum AlignmentBaseline {
211 Auto,
212 Baseline,
213 BeforeEdge,
214 TextBeforeEdge,
215 Middle,
216 Central,
217 AfterEdge,
218 TextAfterEdge,
219 Ideographic,
220 Alphabetic,
221 Hanging,
222 Mathematical,
223}
224
225impl Default for AlignmentBaseline {
226 fn default() -> Self {
227 Self::Auto
228 }
229}
230
231#[allow(missing_docs)]
233#[derive(Clone, Copy, PartialEq, Debug)]
234pub enum BaselineShift {
235 Baseline,
236 Subscript,
237 Superscript,
238 Number(f32),
239}
240
241impl Default for BaselineShift {
242 #[inline]
243 fn default() -> BaselineShift {
244 BaselineShift::Baseline
245 }
246}
247
248#[allow(missing_docs)]
250#[derive(Clone, Copy, PartialEq, Debug)]
251pub enum LengthAdjust {
252 Spacing,
253 SpacingAndGlyphs,
254}
255
256impl Default for LengthAdjust {
257 fn default() -> Self {
258 Self::Spacing
259 }
260}
261
262#[derive(Clone, Copy, PartialEq, Debug)]
267pub enum FontOpticalSizing {
268 Auto,
270 None,
272}
273
274impl Default for FontOpticalSizing {
275 fn default() -> Self {
276 Self::Auto
277 }
278}
279
280#[derive(Clone, Debug)]
287pub struct TextDecorationStyle {
288 pub fill: Option<Fill>,
289 pub stroke: Option<Stroke>,
290}
291
292impl TextDecorationStyle {
293 pub fn fill(&self) -> Option<&Fill> {
295 self.fill.as_ref()
296 }
297
298 pub fn stroke(&self) -> Option<&Stroke> {
300 self.stroke.as_ref()
301 }
302}
303
304#[derive(Clone, Debug)]
306pub struct TextDecoration {
307 pub underline: Option<TextDecorationStyle>,
308 pub overline: Option<TextDecorationStyle>,
309 pub line_through: Option<TextDecorationStyle>,
310}
311
312impl TextDecoration {
313 pub fn underline(&self) -> Option<&TextDecorationStyle> {
315 self.underline.as_ref()
316 }
317
318 pub fn overline(&self) -> Option<&TextDecorationStyle> {
320 self.overline.as_ref()
321 }
322
323 pub fn line_through(&self) -> Option<&TextDecorationStyle> {
325 self.line_through.as_ref()
326 }
327}
328
329#[derive(Clone, Debug)]
333pub struct TextSpan {
334 pub start: usize,
335 pub end: usize,
336 pub fill: Option<Fill>,
337 pub stroke: Option<Stroke>,
338 pub paint_order: PaintOrder,
339 pub font: Font,
340 pub font_size: NonZeroPositiveF32,
341 pub small_caps: bool,
342 pub apply_kerning: bool,
343 pub font_optical_sizing: FontOpticalSizing,
344 pub decoration: TextDecoration,
345 pub dominant_baseline: DominantBaseline,
346 pub alignment_baseline: AlignmentBaseline,
347 pub baseline_shift: Vec<BaselineShift>,
348 pub visible: bool,
349 pub letter_spacing: f32,
350 pub word_spacing: f32,
351 pub text_length: Option<f32>,
352 pub length_adjust: LengthAdjust,
353}
354
355impl TextSpan {
356 pub fn start(&self) -> usize {
360 self.start
361 }
362
363 pub fn end(&self) -> usize {
367 self.end
368 }
369
370 pub fn fill(&self) -> Option<&Fill> {
372 self.fill.as_ref()
373 }
374
375 pub fn stroke(&self) -> Option<&Stroke> {
377 self.stroke.as_ref()
378 }
379
380 pub fn paint_order(&self) -> PaintOrder {
382 self.paint_order
383 }
384
385 pub fn font(&self) -> &Font {
387 &self.font
388 }
389
390 pub fn font_size(&self) -> NonZeroPositiveF32 {
392 self.font_size
393 }
394
395 pub fn small_caps(&self) -> bool {
399 self.small_caps
400 }
401
402 pub fn apply_kerning(&self) -> bool {
406 self.apply_kerning
407 }
408
409 pub fn font_optical_sizing(&self) -> FontOpticalSizing {
415 self.font_optical_sizing
416 }
417
418 pub fn decoration(&self) -> &TextDecoration {
420 &self.decoration
421 }
422
423 pub fn dominant_baseline(&self) -> DominantBaseline {
425 self.dominant_baseline
426 }
427
428 pub fn alignment_baseline(&self) -> AlignmentBaseline {
430 self.alignment_baseline
431 }
432
433 pub fn baseline_shift(&self) -> &[BaselineShift] {
437 &self.baseline_shift
438 }
439
440 pub fn is_visible(&self) -> bool {
442 self.visible
443 }
444
445 pub fn letter_spacing(&self) -> f32 {
447 self.letter_spacing
448 }
449
450 pub fn word_spacing(&self) -> f32 {
452 self.word_spacing
453 }
454
455 pub fn text_length(&self) -> Option<f32> {
457 self.text_length
458 }
459
460 pub fn length_adjust(&self) -> LengthAdjust {
462 self.length_adjust
463 }
464}
465
466#[allow(missing_docs)]
468#[derive(Clone, Copy, PartialEq, Debug)]
469pub enum TextAnchor {
470 Start,
471 Middle,
472 End,
473}
474
475impl Default for TextAnchor {
476 fn default() -> Self {
477 Self::Start
478 }
479}
480
481#[derive(Debug)]
483pub struct TextPath {
484 pub id: NonEmptyString,
485 pub start_offset: f32,
486 pub path: Arc<tiny_skia_path::Path>,
487}
488
489impl TextPath {
490 pub fn id(&self) -> &str {
494 self.id.get()
495 }
496
497 pub fn start_offset(&self) -> f32 {
501 self.start_offset
502 }
503
504 pub fn path(&self) -> &tiny_skia_path::Path {
506 &self.path
507 }
508}
509
510#[derive(Clone, Debug)]
512pub enum TextFlow {
513 Linear,
517 Path(Arc<TextPath>),
519}
520
521#[derive(Clone, Debug)]
525pub struct TextChunk {
526 pub x: Option<f32>,
527 pub y: Option<f32>,
528 pub anchor: TextAnchor,
529 pub spans: Vec<TextSpan>,
530 pub text_flow: TextFlow,
531 pub text: String,
532}
533
534impl TextChunk {
535 pub fn x(&self) -> Option<f32> {
537 self.x
538 }
539
540 pub fn y(&self) -> Option<f32> {
542 self.y
543 }
544
545 pub fn anchor(&self) -> TextAnchor {
547 self.anchor
548 }
549
550 pub fn spans(&self) -> &[TextSpan] {
552 &self.spans
553 }
554
555 pub fn text_flow(&self) -> TextFlow {
557 self.text_flow.clone()
558 }
559
560 pub fn text(&self) -> &str {
562 &self.text
563 }
564}
565
566#[allow(missing_docs)]
568#[derive(Clone, Copy, PartialEq, Debug)]
569pub enum WritingMode {
570 LeftToRight,
571 TopToBottom,
572}
573
574#[derive(Clone, Debug)]
578pub struct Text {
579 pub id: String,
580 pub rendering_mode: TextRendering,
581 pub dx: Vec<f32>,
582 pub dy: Vec<f32>,
583 pub rotate: Vec<f32>,
584 pub writing_mode: WritingMode,
585 pub chunks: Vec<TextChunk>,
586 pub abs_transform: Transform,
587 pub bounding_box: Rect,
588 pub abs_bounding_box: Rect,
589 pub stroke_bounding_box: Rect,
590 pub abs_stroke_bounding_box: Rect,
591 pub flattened: Box<Group>,
592 #[cfg(feature = "text")]
593 pub layouted: Vec<Span>,
594}
595
596impl Text {
597 pub fn id(&self) -> &str {
603 &self.id
604 }
605
606 pub fn rendering_mode(&self) -> TextRendering {
610 self.rendering_mode
611 }
612
613 pub fn dx(&self) -> &[f32] {
617 &self.dx
618 }
619
620 pub fn dy(&self) -> &[f32] {
624 &self.dy
625 }
626
627 pub fn rotate(&self) -> &[f32] {
631 &self.rotate
632 }
633
634 pub fn writing_mode(&self) -> WritingMode {
636 self.writing_mode
637 }
638
639 pub fn chunks(&self) -> &[TextChunk] {
641 &self.chunks
642 }
643
644 pub fn abs_transform(&self) -> Transform {
651 self.abs_transform
652 }
653
654 pub fn bounding_box(&self) -> Rect {
666 self.bounding_box
667 }
668
669 pub fn abs_bounding_box(&self) -> Rect {
673 self.abs_bounding_box
674 }
675
676 pub fn stroke_bounding_box(&self) -> Rect {
682 self.stroke_bounding_box
683 }
684
685 pub fn abs_stroke_bounding_box(&self) -> Rect {
687 self.abs_stroke_bounding_box
688 }
689
690 pub fn flattened(&self) -> &Group {
707 &self.flattened
708 }
709
710 #[cfg(feature = "text")]
716 pub fn layouted(&self) -> &[Span] {
717 &self.layouted
718 }
719
720 pub(crate) fn subroots(&self, f: &mut dyn FnMut(&Group)) {
721 f(&self.flattened);
722 }
723}