style/values/generics/
border.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 borders.
6
7use crate::values::generics::rect::Rect;
8use crate::values::generics::size::Size2D;
9use crate::Zero;
10use std::fmt::{self, Write};
11use style_traits::{CssWriter, ToCss};
12
13/// A generic value for a single side of a `border-image-width` property.
14#[derive(
15    Animate,
16    Clone,
17    ComputeSquaredDistance,
18    Copy,
19    Debug,
20    MallocSizeOf,
21    Parse,
22    PartialEq,
23    SpecifiedValueInfo,
24    ToAnimatedValue,
25    ToAnimatedZero,
26    ToComputedValue,
27    ToCss,
28    ToResolvedValue,
29    ToShmem,
30)]
31#[repr(C, u8)]
32pub enum GenericBorderImageSideWidth<LP, N> {
33    /// `<number>`
34    ///
35    /// NOTE: Numbers need to be before length-percentagess, in order to parse
36    /// them first, since `0` should be a number, not the `0px` length.
37    Number(N),
38    /// `<length-or-percentage>`
39    LengthPercentage(LP),
40    /// `auto`
41    Auto,
42}
43
44pub use self::GenericBorderImageSideWidth as BorderImageSideWidth;
45
46/// A generic value for the `border-image-slice` property.
47#[derive(
48    Animate,
49    Clone,
50    ComputeSquaredDistance,
51    Copy,
52    Debug,
53    MallocSizeOf,
54    PartialEq,
55    SpecifiedValueInfo,
56    ToAnimatedValue,
57    ToAnimatedZero,
58    ToComputedValue,
59    ToCss,
60    ToResolvedValue,
61    ToShmem,
62)]
63#[repr(C)]
64pub struct GenericBorderImageSlice<NumberOrPercentage> {
65    /// The offsets.
66    #[css(field_bound)]
67    pub offsets: Rect<NumberOrPercentage>,
68    /// Whether to fill the middle part.
69    #[animation(constant)]
70    #[css(represents_keyword)]
71    pub fill: bool,
72}
73
74pub use self::GenericBorderImageSlice as BorderImageSlice;
75
76/// A generic value for the `border-*-radius` longhand properties.
77#[derive(
78    Animate,
79    Clone,
80    ComputeSquaredDistance,
81    Copy,
82    Debug,
83    Deserialize,
84    MallocSizeOf,
85    PartialEq,
86    SpecifiedValueInfo,
87    Serialize,
88    ToAnimatedValue,
89    ToAnimatedZero,
90    ToComputedValue,
91    ToCss,
92    ToResolvedValue,
93    ToShmem,
94)]
95#[repr(C)]
96pub struct GenericBorderCornerRadius<L>(
97    #[css(field_bound)]
98    #[shmem(field_bound)]
99    pub Size2D<L>,
100);
101
102pub use self::GenericBorderCornerRadius as BorderCornerRadius;
103
104impl<L> BorderCornerRadius<L> {
105    /// Trivially create a `BorderCornerRadius`.
106    pub fn new(w: L, h: L) -> Self {
107        BorderCornerRadius(Size2D::new(w, h))
108    }
109}
110
111impl<L: Zero> Zero for BorderCornerRadius<L> {
112    fn zero() -> Self {
113        BorderCornerRadius(Size2D::zero())
114    }
115
116    fn is_zero(&self) -> bool {
117        self.0.is_zero()
118    }
119}
120
121/// A generic value for the `border-spacing` property.
122#[derive(
123    Animate,
124    Clone,
125    ComputeSquaredDistance,
126    Copy,
127    Debug,
128    MallocSizeOf,
129    PartialEq,
130    SpecifiedValueInfo,
131    ToAnimatedValue,
132    ToAnimatedZero,
133    ToComputedValue,
134    ToCss,
135    ToResolvedValue,
136    ToShmem,
137)]
138#[repr(transparent)]
139pub struct GenericBorderSpacing<L>(
140    #[css(field_bound)]
141    #[shmem(field_bound)]
142    pub Size2D<L>,
143);
144
145pub use self::GenericBorderSpacing as BorderSpacing;
146impl<L> BorderSpacing<L> {
147    /// Trivially create a `BorderCornerRadius`.
148    pub fn new(w: L, h: L) -> Self {
149        BorderSpacing(Size2D::new(w, h))
150    }
151}
152
153/// A generic value for `border-radius` and `inset()`.
154///
155/// <https://drafts.csswg.org/css-backgrounds-3/#border-radius>
156#[derive(
157    Animate,
158    Clone,
159    ComputeSquaredDistance,
160    Copy,
161    Debug,
162    Deserialize,
163    MallocSizeOf,
164    PartialEq,
165    SpecifiedValueInfo,
166    Serialize,
167    ToAnimatedValue,
168    ToComputedValue,
169    ToResolvedValue,
170    ToShmem,
171)]
172#[repr(C)]
173pub struct GenericBorderRadius<LengthPercentage> {
174    /// The top left radius.
175    #[shmem(field_bound)]
176    pub top_left: GenericBorderCornerRadius<LengthPercentage>,
177    /// The top right radius.
178    pub top_right: GenericBorderCornerRadius<LengthPercentage>,
179    /// The bottom right radius.
180    pub bottom_right: GenericBorderCornerRadius<LengthPercentage>,
181    /// The bottom left radius.
182    pub bottom_left: GenericBorderCornerRadius<LengthPercentage>,
183}
184
185pub use self::GenericBorderRadius as BorderRadius;
186
187impl<L> BorderRadius<L> {
188    /// Returns a new `BorderRadius<L>`.
189    #[inline]
190    pub fn new(
191        tl: BorderCornerRadius<L>,
192        tr: BorderCornerRadius<L>,
193        br: BorderCornerRadius<L>,
194        bl: BorderCornerRadius<L>,
195    ) -> Self {
196        BorderRadius {
197            top_left: tl,
198            top_right: tr,
199            bottom_right: br,
200            bottom_left: bl,
201        }
202    }
203
204    /// Serialises two given rects following the syntax of the `border-radius``
205    /// property.
206    pub fn serialize_rects<W>(
207        widths: Rect<&L>,
208        heights: Rect<&L>,
209        dest: &mut CssWriter<W>,
210    ) -> fmt::Result
211    where
212        L: PartialEq + ToCss,
213        W: Write,
214    {
215        widths.to_css(dest)?;
216        if widths != heights {
217            dest.write_str(" / ")?;
218            heights.to_css(dest)?;
219        }
220        Ok(())
221    }
222}
223
224impl<L: Zero> Zero for BorderRadius<L> {
225    fn zero() -> Self {
226        Self::new(
227            BorderCornerRadius::<L>::zero(),
228            BorderCornerRadius::<L>::zero(),
229            BorderCornerRadius::<L>::zero(),
230            BorderCornerRadius::<L>::zero(),
231        )
232    }
233
234    fn is_zero(&self) -> bool {
235        self.top_left.is_zero()
236            && self.top_right.is_zero()
237            && self.bottom_right.is_zero()
238            && self.bottom_left.is_zero()
239    }
240}
241
242impl<L> ToCss for BorderRadius<L>
243where
244    L: PartialEq + ToCss,
245{
246    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
247    where
248        W: Write,
249    {
250        let BorderRadius {
251            top_left: BorderCornerRadius(ref tl),
252            top_right: BorderCornerRadius(ref tr),
253            bottom_right: BorderCornerRadius(ref br),
254            bottom_left: BorderCornerRadius(ref bl),
255        } = *self;
256
257        let widths = Rect::new(&tl.width, &tr.width, &br.width, &bl.width);
258        let heights = Rect::new(&tl.height, &tr.height, &br.height, &bl.height);
259
260        Self::serialize_rects(widths, heights, dest)
261    }
262}