use std::fmt;
use cssparser::{Parser, Token};
use typed_builder::TypedBuilder;
use crate::layout::style::{
Animatable, CssSyntaxKind, CssToken, FromCss, MakeComputed, ParseResult, ToCss,
declare_enum_from_css_impl, unexpected_token,
};
#[derive(Debug, Clone, Copy, PartialEq, Default, TypedBuilder)]
#[non_exhaustive]
#[builder(field_defaults(default))]
pub struct TextFit {
pub mode: TextFitMode,
pub target: TextFitTarget,
pub limit: Option<f32>,
}
impl MakeComputed for TextFit {}
impl Animatable for TextFit {}
impl<'i> FromCss<'i> for TextFit {
fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
let mode = TextFitMode::from_css(input)?;
let target = input.try_parse(TextFitTarget::from_css).unwrap_or_default();
let limit: Option<f32> = input
.try_parse(|input| -> ParseResult<'i, f32> {
let location = input.current_source_location();
match input.next()? {
Token::Percentage { unit_value, .. } => Ok(unit_value.max(0.0)),
token => Err(unexpected_token!(location, token)),
}
})
.ok();
if !input.is_exhausted() {
return Err(input.new_error_for_next_token());
}
Ok(Self {
mode,
target,
limit,
})
}
const VALID_TOKENS: &'static [CssToken] = &[
CssToken::Keyword("none"),
CssToken::Keyword("grow"),
CssToken::Keyword("shrink"),
CssToken::Keyword("consistent"),
CssToken::Keyword("per-line"),
CssToken::Keyword("per-line-all"),
CssToken::Syntax(CssSyntaxKind::Percentage),
];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum TextFitMode {
#[default]
None,
Grow,
Shrink,
}
declare_enum_from_css_impl!(
TextFitMode,
"none" => TextFitMode::None,
"grow" => TextFitMode::Grow,
"shrink" => TextFitMode::Shrink,
);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum TextFitTarget {
#[default]
Consistent,
PerLine,
PerLineAll,
}
declare_enum_from_css_impl!(
TextFitTarget,
"consistent" => TextFitTarget::Consistent,
"per-line" => TextFitTarget::PerLine,
"per-line-all" => TextFitTarget::PerLineAll,
);
impl ToCss for TextFit {
fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
self.mode.to_css(dest)?;
if self.target != TextFitTarget::Consistent {
dest.write_char(' ')?;
self.target.to_css(dest)?;
}
if let Some(limit) = self.limit {
dest.write_char(' ')?;
write!(dest, "{}%", limit * 100.0)?;
}
Ok(())
}
}