Skip to main content

appcore_filemaker/
source_text.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: source_text.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/08/30 05:00:00 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/08/30 05:00:00 by dnettoRaw
8//      ###########      S: 1.0.2-rc
9// =============================================================================
10
11use serde::{Deserialize, Serialize};
12
13use crate::{ErrorCode, FileMakerError, Length, Result, TextIr, TextOverflow, Unit, WritingMode};
14
15/// Declarative text measurement and overflow options.
16#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
17#[serde(default, deny_unknown_fields)]
18pub struct TextSourceOptions {
19    /// Overflow behavior.
20    pub overflow: TextOverflow,
21    /// Optional maximum number of resolved lines.
22    pub max_lines: Option<usize>,
23    /// Minimum size used by `shrink`; must be absolute.
24    pub min_font_size: Option<Length>,
25    /// Line-height multiplier in millionths.
26    pub line_height: u32,
27    /// Horizontal lines or top-to-bottom right-to-left vertical columns.
28    pub writing_mode: WritingMode,
29}
30
31impl Default for TextSourceOptions {
32    fn default() -> Self {
33        Self {
34            overflow: TextOverflow::Wrap,
35            max_lines: None,
36            min_font_size: Some(Length::Absolute(Unit::from_raw(6_000_000))),
37            line_height: 1_200_000,
38            writing_mode: WritingMode::Horizontal,
39        }
40    }
41}
42
43pub(crate) fn validate_text_options(options: &TextSourceOptions) -> Result<()> {
44    let minimum = options
45        .min_font_size
46        .map(|value| value.resolve(Unit::ZERO, Unit::ZERO))
47        .transpose()?
48        .flatten();
49    if options.max_lines == Some(0)
50        || !(500_000..=4_000_000).contains(&options.line_height)
51        || minimum.is_some_and(|value| value <= Unit::ZERO)
52        || options
53            .min_font_size
54            .is_some_and(|value| !matches!(value, Length::Absolute(_)))
55    {
56        return Err(FileMakerError::new(
57            ErrorCode::SchemaField,
58            "text options contain an invalid line or minimum-font constraint",
59        ));
60    }
61    Ok(())
62}
63
64pub(crate) fn convert_text_options(options: TextSourceOptions) -> TextIr {
65    TextIr {
66        overflow: options.overflow,
67        max_lines: options.max_lines,
68        min_font_size: options.min_font_size,
69        line_height: options.line_height,
70        writing_mode: options.writing_mode,
71    }
72}