takumi_css/style/properties/
text_fit.rs1use std::fmt;
2
3use cssparser::{Parser, Token};
4use typed_builder::TypedBuilder;
5
6use crate::style::{
7 Animatable, CssSyntaxKind, CssToken, FromCss, MakeComputed, ParseResult, ToCss,
8 declare_enum_from_css_impl, unexpected_token,
9};
10
11#[derive(Debug, Clone, Copy, PartialEq, Default, TypedBuilder)]
13#[builder(field_defaults(default))]
14#[non_exhaustive]
15pub struct TextFit {
16 pub mode: TextFitMode,
18 pub target: TextFitTarget,
20 pub limit: Option<f32>,
22}
23
24impl MakeComputed for TextFit {}
25impl Animatable for TextFit {}
26
27impl<'i> FromCss<'i> for TextFit {
28 fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
31 let mode = TextFitMode::from_css(input)?;
32
33 let target = input.try_parse(TextFitTarget::from_css).unwrap_or_default();
34
35 let limit: Option<f32> = input
36 .try_parse(|input| -> ParseResult<'i, f32> {
37 let location = input.current_source_location();
38 match input.next()? {
39 Token::Percentage { unit_value, .. } => Ok(unit_value.max(0.0)),
40 token => Err(unexpected_token!(location, token)),
41 }
42 })
43 .ok();
44
45 if !input.is_exhausted() {
47 return Err(input.new_error_for_next_token());
48 }
49
50 Ok(Self {
51 mode,
52 target,
53 limit,
54 })
55 }
56
57 const VALID_TOKENS: &'static [CssToken] = &[
58 CssToken::Keyword("none"),
59 CssToken::Keyword("grow"),
60 CssToken::Keyword("shrink"),
61 CssToken::Keyword("consistent"),
62 CssToken::Keyword("per-line"),
63 CssToken::Keyword("per-line-all"),
64 CssToken::Syntax(CssSyntaxKind::Percentage),
65 ];
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
70pub enum TextFitMode {
71 #[default]
73 None,
74 Grow,
76 Shrink,
78}
79
80declare_enum_from_css_impl!(
81 TextFitMode,
82 "none" => TextFitMode::None,
83 "grow" => TextFitMode::Grow,
84 "shrink" => TextFitMode::Shrink,
85);
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
89#[non_exhaustive]
90pub enum TextFitTarget {
91 #[default]
93 Consistent,
94 PerLine,
96 PerLineAll,
98}
99
100declare_enum_from_css_impl!(
101 TextFitTarget,
102 "consistent" => TextFitTarget::Consistent,
103 "per-line" => TextFitTarget::PerLine,
104 "per-line-all" => TextFitTarget::PerLineAll,
105);
106
107impl ToCss for TextFit {
108 fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
109 self.mode.to_css(dest)?;
110 if self.target != TextFitTarget::Consistent {
111 dest.write_char(' ')?;
112 self.target.to_css(dest)?;
113 }
114 if let Some(limit) = self.limit {
115 dest.write_char(' ')?;
116 write!(dest, "{}%", limit * 100.0)?;
117 }
118 Ok(())
119 }
120}