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