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}