rustmotion-core 0.8.0

Core types, traits, and rendering utilities for rustmotion
Documentation
use super::style::CssStyle;

pub fn inherit_from(parent: &CssStyle, child: &mut CssStyle) {
    if child.color.is_none() {
        child.color = parent.color.clone();
    }
    if child.font_family.is_none() {
        child.font_family = parent.font_family.clone();
    }
    if child.font_size.is_none() {
        child.font_size = parent.font_size.clone();
    }
    if child.font_weight.is_none() {
        child.font_weight = parent.font_weight.clone();
    }
    if child.font_style.is_none() {
        child.font_style = parent.font_style;
    }
    if child.line_height.is_none() {
        child.line_height = parent.line_height.clone();
    }
    if child.letter_spacing.is_none() {
        child.letter_spacing = parent.letter_spacing.clone();
    }
    if child.text_align.is_none() {
        child.text_align = parent.text_align;
    }
    if child.white_space.is_none() {
        child.white_space = parent.white_space;
    }
    if child.overflow_wrap.is_none() {
        child.overflow_wrap = parent.overflow_wrap;
    }
    if child.visibility.is_none() {
        child.visibility = parent.visibility;
    }
    if child.text_decoration.is_none() {
        child.text_decoration = parent.text_decoration.clone();
    }
}

pub fn overlay_resolved_typography(resolved: &CssStyle, own: &mut CssStyle) {
    if resolved.color.is_some() {
        own.color = resolved.color.clone();
    }
    if resolved.font_family.is_some() {
        own.font_family = resolved.font_family.clone();
    }
    if resolved.font_size.is_some() {
        own.font_size = resolved.font_size.clone();
    }
    if resolved.font_weight.is_some() {
        own.font_weight = resolved.font_weight.clone();
    }
    if resolved.font_style.is_some() {
        own.font_style = resolved.font_style;
    }
    if resolved.line_height.is_some() {
        own.line_height = resolved.line_height.clone();
    }
    if resolved.letter_spacing.is_some() {
        own.letter_spacing = resolved.letter_spacing.clone();
    }
    if resolved.text_align.is_some() {
        own.text_align = resolved.text_align;
    }
    if resolved.white_space.is_some() {
        own.white_space = resolved.white_space;
    }
    if resolved.overflow_wrap.is_some() {
        own.overflow_wrap = resolved.overflow_wrap;
    }
    if resolved.visibility.is_some() {
        own.visibility = resolved.visibility;
    }
    if resolved.text_decoration.is_some() {
        own.text_decoration = resolved.text_decoration.clone();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::css::style::{Color, Display, FontStyle, TextAlign};

    #[test]
    fn child_inherits_color_when_unset() {
        let parent = CssStyle {
            color: Some(Color::String("#ff0000".into())),
            ..Default::default()
        };
        let mut child = CssStyle::default();
        inherit_from(&parent, &mut child);
        assert!(matches!(child.color, Some(Color::String(_))));
    }

    #[test]
    fn child_overrides_parent_color() {
        let parent = CssStyle {
            color: Some(Color::String("#ff0000".into())),
            ..Default::default()
        };
        let mut child = CssStyle {
            color: Some(Color::String("#00ff00".into())),
            ..Default::default()
        };
        inherit_from(&parent, &mut child);
        match child.color {
            Some(Color::String(s)) => assert_eq!(s, "#00ff00"),
            _ => panic!("expected child color preserved"),
        }
    }

    #[test]
    fn non_inheritable_not_propagated() {
        let parent = CssStyle {
            display: Some(Display::Flex),
            ..Default::default()
        };
        let mut child = CssStyle::default();
        inherit_from(&parent, &mut child);
        assert!(child.display.is_none());
    }

    #[test]
    fn font_props_inherited() {
        let parent = CssStyle {
            font_family: Some("Arial".into()),
            font_style: Some(FontStyle::Italic),
            text_align: Some(TextAlign::Center),
            ..Default::default()
        };
        let mut child = CssStyle::default();
        inherit_from(&parent, &mut child);
        assert_eq!(child.font_family.as_deref(), Some("Arial"));
        assert_eq!(child.font_style, Some(FontStyle::Italic));
        assert_eq!(child.text_align, Some(TextAlign::Center));
    }

    #[test]
    fn overlay_resolved_typography_replaces_a_component_own_static_font_size() {
        use crate::css::units::Length;

        let resolved = CssStyle {
            font_size: Some(Length::Px(120.0)),
            ..Default::default()
        };
        let mut own = CssStyle {
            font_size: Some(Length::Px(20.0)),
            ..Default::default()
        };
        overlay_resolved_typography(&resolved, &mut own);
        assert_eq!(
            own.font_size,
            Some(Length::Px(120.0)),
            "the box's own already-animated resolved font-size must win over the component's \
             declared static one, unlike inherit_from's fill-only-if-none rule"
        );
    }

    #[test]
    fn overlay_resolved_typography_replaces_a_component_own_static_letter_spacing() {
        use crate::css::units::Length;

        let resolved = CssStyle {
            letter_spacing: Some(Length::Px(18.0)),
            ..Default::default()
        };
        let mut own = CssStyle {
            letter_spacing: Some(Length::Px(0.0)),
            ..Default::default()
        };
        overlay_resolved_typography(&resolved, &mut own);
        assert_eq!(own.letter_spacing, Some(Length::Px(18.0)));
    }

    #[test]
    fn overlay_resolved_typography_leaves_a_field_alone_when_resolved_lacks_it() {
        let resolved = CssStyle::default();
        let mut own = CssStyle {
            color: Some(Color::String("#00ff00".into())),
            ..Default::default()
        };
        overlay_resolved_typography(&resolved, &mut own);
        match own.color {
            Some(Color::String(s)) => assert_eq!(s, "#00ff00"),
            other => panic!("resolved had no color; own's must be left alone, got {other:?}"),
        }
    }
}