style/values/generics/
ratio.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Generic types for CSS values related to <ratio>.
6//! https://drafts.csswg.org/css-values/#ratios
7
8use crate::derives::*;
9use crate::{One, Zero};
10use std::fmt::{self, Write};
11use style_traits::{CssWriter, ToCss};
12
13/// A generic value for the `<ratio>` value.
14#[derive(
15    Clone,
16    Copy,
17    Debug,
18    MallocSizeOf,
19    PartialEq,
20    SpecifiedValueInfo,
21    ToAnimatedValue,
22    ToComputedValue,
23    ToResolvedValue,
24    ToShmem,
25)]
26#[repr(C)]
27pub struct Ratio<N>(pub N, pub N);
28
29impl<N> ToCss for Ratio<N>
30where
31    N: ToCss,
32{
33    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
34    where
35        W: Write,
36    {
37        self.0.to_css(dest)?;
38        // Even though 1 could be omitted, we don't per
39        // https://drafts.csswg.org/css-values-4/#ratio-value:
40        //
41        //     The second <number> is optional, defaulting to 1. However,
42        //     <ratio> is always serialized with both components.
43        //
44        // And for compat reasons, see bug 1669742.
45        //
46        // We serialize with spaces for consistency with all other
47        // slash-delimited things, see
48        // https://github.com/w3c/csswg-drafts/issues/4282
49        dest.write_str(" / ")?;
50        self.1.to_css(dest)?;
51        Ok(())
52    }
53}
54
55impl<N> Ratio<N>
56where
57    N: Zero + One,
58{
59    /// Returns true if this is a degenerate ratio.
60    /// https://drafts.csswg.org/css-values/#degenerate-ratio
61    #[inline]
62    pub fn is_degenerate(&self) -> bool {
63        self.0.is_zero() || self.1.is_zero()
64    }
65
66    /// Returns the used value. A ratio of 0/0 behaves as the ratio 1/0.
67    /// https://drafts.csswg.org/css-values-4/#ratios
68    pub fn used_value(self) -> Self {
69        if self.0.is_zero() && self.1.is_zero() {
70            Self(One::one(), Zero::zero())
71        } else {
72            self
73        }
74    }
75}
76
77impl<N> Zero for Ratio<N>
78where
79    N: Zero + One,
80{
81    fn zero() -> Self {
82        Self(Zero::zero(), One::one())
83    }
84
85    fn is_zero(&self) -> bool {
86        self.0.is_zero()
87    }
88}