Skip to main content

whisker_css/keyword/
background.rs

1//! Background-related keyword enums.
2//!
3//! References:
4//! - <https://lynxjs.org/api/css/properties/background-repeat>
5//! - <https://lynxjs.org/api/css/properties/background-clip>
6//! - <https://lynxjs.org/api/css/properties/background-origin>
7//! - <https://lynxjs.org/api/css/properties/background-size>
8//! - <https://lynxjs.org/api/css/properties/background-attachment>
9
10use core::fmt;
11
12use crate::data_type::LengthPercentage;
13use crate::to_css::ToCss;
14
15/// The `background-repeat` keyword.
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
17pub enum BackgroundRepeat {
18    /// `repeat` — tile both axes. Default.
19    Repeat,
20    /// `no-repeat` — no tiling.
21    NoRepeat,
22    /// `repeat-x` — tile horizontally only.
23    RepeatX,
24    /// `repeat-y` — tile vertically only.
25    RepeatY,
26    /// `space` — tile with extra space between tiles to fill the box.
27    Space,
28    /// `round` — tile, scaling each tile so an integer number fit.
29    Round,
30}
31
32impl ToCss for BackgroundRepeat {
33    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
34        dest.write_str(match self {
35            BackgroundRepeat::Repeat => "repeat",
36            BackgroundRepeat::NoRepeat => "no-repeat",
37            BackgroundRepeat::RepeatX => "repeat-x",
38            BackgroundRepeat::RepeatY => "repeat-y",
39            BackgroundRepeat::Space => "space",
40            BackgroundRepeat::Round => "round",
41        })
42    }
43}
44
45/// The `background-clip` keyword.
46#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
47pub enum BackgroundClip {
48    /// `border-box` — clip to the border box. Default.
49    BorderBox,
50    /// `padding-box` — clip to the padding box.
51    PaddingBox,
52    /// `content-box` — clip to the content box.
53    ContentBox,
54    /// `text` — clip to the foreground text.
55    Text,
56}
57
58impl ToCss for BackgroundClip {
59    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
60        dest.write_str(match self {
61            BackgroundClip::BorderBox => "border-box",
62            BackgroundClip::PaddingBox => "padding-box",
63            BackgroundClip::ContentBox => "content-box",
64            BackgroundClip::Text => "text",
65        })
66    }
67}
68
69/// The `background-origin` keyword.
70#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
71pub enum BackgroundOrigin {
72    /// `border-box` — origin at the border box.
73    BorderBox,
74    /// `padding-box` — origin at the padding box. Default.
75    PaddingBox,
76    /// `content-box` — origin at the content box.
77    ContentBox,
78}
79
80impl ToCss for BackgroundOrigin {
81    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
82        dest.write_str(match self {
83            BackgroundOrigin::BorderBox => "border-box",
84            BackgroundOrigin::PaddingBox => "padding-box",
85            BackgroundOrigin::ContentBox => "content-box",
86        })
87    }
88}
89
90/// The `background-attachment` keyword.
91#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
92pub enum BackgroundAttachment {
93    /// `scroll` — background scrolls with the element. Default.
94    Scroll,
95    /// `fixed` — background is fixed relative to the viewport.
96    Fixed,
97    /// `local` — background scrolls with the element's content.
98    Local,
99}
100
101impl ToCss for BackgroundAttachment {
102    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
103        dest.write_str(match self {
104            BackgroundAttachment::Scroll => "scroll",
105            BackgroundAttachment::Fixed => "fixed",
106            BackgroundAttachment::Local => "local",
107        })
108    }
109}
110
111/// The `background-size` value: a keyword or an explicit pair of
112/// length-percentages.
113#[derive(Clone, Debug, PartialEq)]
114pub enum BackgroundSize {
115    /// `auto` — use the intrinsic size.
116    Auto,
117    /// `cover` — scale to cover the entire box, possibly cropping.
118    Cover,
119    /// `contain` — scale to fit within the box without cropping.
120    Contain,
121    /// Explicit width × height.
122    Explicit(LengthPercentage, LengthPercentage),
123}
124
125impl ToCss for BackgroundSize {
126    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
127        match self {
128            BackgroundSize::Auto => dest.write_str("auto"),
129            BackgroundSize::Cover => dest.write_str("cover"),
130            BackgroundSize::Contain => dest.write_str("contain"),
131            BackgroundSize::Explicit(w, h) => {
132                w.to_css(dest)?;
133                dest.write_char(' ')?;
134                h.to_css(dest)
135            }
136        }
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use crate::data_type::{Length, Percentage};
144
145    #[test]
146    fn background_repeat_all() {
147        let cases = [
148            (BackgroundRepeat::Repeat, "repeat"),
149            (BackgroundRepeat::NoRepeat, "no-repeat"),
150            (BackgroundRepeat::RepeatX, "repeat-x"),
151            (BackgroundRepeat::RepeatY, "repeat-y"),
152            (BackgroundRepeat::Space, "space"),
153            (BackgroundRepeat::Round, "round"),
154        ];
155        for (k, expected) in cases {
156            assert_eq!(k.to_css_string(), expected);
157        }
158    }
159
160    #[test]
161    fn background_clip_all() {
162        let cases = [
163            (BackgroundClip::BorderBox, "border-box"),
164            (BackgroundClip::PaddingBox, "padding-box"),
165            (BackgroundClip::ContentBox, "content-box"),
166            (BackgroundClip::Text, "text"),
167        ];
168        for (k, expected) in cases {
169            assert_eq!(k.to_css_string(), expected);
170        }
171    }
172
173    #[test]
174    fn background_origin_all() {
175        let cases = [
176            (BackgroundOrigin::BorderBox, "border-box"),
177            (BackgroundOrigin::PaddingBox, "padding-box"),
178            (BackgroundOrigin::ContentBox, "content-box"),
179        ];
180        for (k, expected) in cases {
181            assert_eq!(k.to_css_string(), expected);
182        }
183    }
184
185    #[test]
186    fn background_attachment_all() {
187        let cases = [
188            (BackgroundAttachment::Scroll, "scroll"),
189            (BackgroundAttachment::Fixed, "fixed"),
190            (BackgroundAttachment::Local, "local"),
191        ];
192        for (k, expected) in cases {
193            assert_eq!(k.to_css_string(), expected);
194        }
195    }
196
197    #[test]
198    fn background_size_keywords_and_explicit() {
199        assert_eq!(BackgroundSize::Auto.to_css_string(), "auto");
200        assert_eq!(BackgroundSize::Cover.to_css_string(), "cover");
201        assert_eq!(BackgroundSize::Contain.to_css_string(), "contain");
202        let explicit = BackgroundSize::Explicit(Length::Px(100.0).into(), Percentage(50.0).into());
203        assert_eq!(explicit.to_css_string(), "100px 50%");
204    }
205}