Skip to main content

style/values/generics/
box.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 box properties.
6
7use crate::derives::*;
8use crate::values::animated::ToAnimatedZero;
9use crate::values::generics::Optional;
10use crate::Zero;
11use std::fmt::{self, Write};
12use style_traits::values::SequenceWriter;
13use style_traits::{CssWriter, ToCss};
14
15#[derive(
16    Animate,
17    Clone,
18    ComputeSquaredDistance,
19    Copy,
20    Debug,
21    FromPrimitive,
22    MallocSizeOf,
23    Parse,
24    PartialEq,
25    SpecifiedValueInfo,
26    ToAnimatedValue,
27    ToComputedValue,
28    ToCss,
29    ToResolvedValue,
30    ToShmem,
31    ToTyped,
32)]
33#[repr(u8)]
34#[allow(missing_docs)]
35pub enum BaselineShiftKeyword {
36    /// Lower by the offset appropriate for subscripts of the parent’s box. The UA may use the
37    /// parent’s font metrics to find this offset; otherwise it defaults to dropping by one
38    /// fifth of the parent’s used font-size.
39    Sub,
40    /// Raise by the offset appropriate for superscripts of the parent’s box. The UA may use the
41    /// parent’s font metrics to find this offset; otherwise it defaults to raising by one third
42    /// of the parent’s used font-size.
43    Super,
44    /// Align the line-over edge of the aligned subtree with the line-over edge of the line box.
45    Top,
46    /// Align the center of the aligned subtree with the center of the line box.
47    Center,
48    /// Align the line-under edge of the aligned subtree with the line-under edge of the line box.
49    Bottom,
50}
51
52/// A generic value for the `baseline-shift` property.
53/// https://drafts.csswg.org/css-inline-3/#baseline-shift
54#[derive(
55    Animate,
56    Clone,
57    ComputeSquaredDistance,
58    Copy,
59    Debug,
60    MallocSizeOf,
61    PartialEq,
62    SpecifiedValueInfo,
63    ToAnimatedValue,
64    ToComputedValue,
65    ToCss,
66    ToResolvedValue,
67    ToShmem,
68    ToTyped,
69)]
70#[repr(C, u8)]
71pub enum GenericBaselineShift<LengthPercentage> {
72    /// One of the baseline-shift keywords
73    Keyword(BaselineShiftKeyword),
74    /// Raise (positive value) or lower (negative value) by the specified length or specified percentage of the line-height.
75    Length(LengthPercentage),
76}
77
78pub use self::GenericBaselineShift as BaselineShift;
79
80impl<L: Zero> BaselineShift<L> {
81    /// Returns the initial `0` value.
82    #[inline]
83    pub fn zero() -> Self {
84        BaselineShift::Length(Zero::zero())
85    }
86}
87
88impl<L> ToAnimatedZero for BaselineShift<L> {
89    fn to_animated_zero(&self) -> Result<Self, ()> {
90        Err(())
91    }
92}
93
94/// https://drafts.csswg.org/css-sizing-4/#intrinsic-size-override
95#[derive(
96    Animate,
97    Clone,
98    ComputeSquaredDistance,
99    Debug,
100    MallocSizeOf,
101    PartialEq,
102    SpecifiedValueInfo,
103    ToComputedValue,
104    ToAnimatedValue,
105    ToAnimatedZero,
106    ToResolvedValue,
107    ToShmem,
108    ToTyped,
109)]
110#[value_info(other_values = "auto")]
111#[repr(C, u8)]
112pub enum GenericContainIntrinsicSize<L> {
113    /// The keyword `none`.
114    None,
115    /// The keywords 'auto none',
116    AutoNone,
117    /// A non-negative length.
118    Length(L),
119    /// "auto <Length>"
120    AutoLength(L),
121}
122
123pub use self::GenericContainIntrinsicSize as ContainIntrinsicSize;
124
125impl<L: ToCss> ToCss for ContainIntrinsicSize<L> {
126    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
127    where
128        W: Write,
129    {
130        match *self {
131            Self::None => dest.write_str("none"),
132            Self::AutoNone => dest.write_str("auto none"),
133            Self::Length(ref l) => l.to_css(dest),
134            Self::AutoLength(ref l) => {
135                dest.write_str("auto ")?;
136                l.to_css(dest)
137            },
138        }
139    }
140}
141
142/// A block ellipsis for line clamping.
143#[derive(
144    Clone,
145    Debug,
146    Eq,
147    MallocSizeOf,
148    PartialEq,
149    Parse,
150    SpecifiedValueInfo,
151    ToAnimatedValue,
152    ToComputedValue,
153    ToCss,
154    ToResolvedValue,
155    ToShmem,
156)]
157#[repr(C, u8)]
158pub enum BlockEllipsis {
159    /// Display the ellipsis character.
160    Ellipsis,
161    /// Do not display an ellipsis.
162    NoEllipsis,
163    /// Display the given string.
164    String(crate::values::AtomString),
165}
166
167impl BlockEllipsis {
168    /// Returns whether this value is `ellipsis`.
169    pub fn is_ellipsis(&self) -> bool {
170        matches!(self, Self::Ellipsis)
171    }
172}
173
174/// A keyword for the maximum lines used by `line-clamp`.
175#[derive(
176    Animate,
177    Clone,
178    Debug,
179    Eq,
180    MallocSizeOf,
181    PartialEq,
182    Parse,
183    SpecifiedValueInfo,
184    ToAnimatedValue,
185    ToComputedValue,
186    ToCss,
187    ToResolvedValue,
188    ToShmem,
189)]
190#[repr(u8)]
191pub enum MaxLinesKeyword {
192    /// No block-size clamping is applied.
193    None,
194    /// Clamp using the available block size.
195    Auto,
196}
197
198impl MaxLinesKeyword {
199    /// Returns whether this keyword is `none`.
200    pub fn is_none(&self) -> bool {
201        matches!(self, Self::None)
202    }
203}
204
205/// A generic value for the maximum lines used by `line-clamp`.
206/// <https://drafts.csswg.org/css-overflow-4/#propdef-max-lines>
207#[derive(
208    Animate,
209    Clone,
210    ComputeSquaredDistance,
211    Debug,
212    MallocSizeOf,
213    PartialEq,
214    SpecifiedValueInfo,
215    ToAnimatedValue,
216    ToAnimatedZero,
217    ToComputedValue,
218    ToCss,
219    ToResolvedValue,
220    ToShmem,
221    ToTyped,
222)]
223#[repr(C)]
224#[typed(todo_derive_fields)]
225pub struct GenericMaxLines<I> {
226    /// The maximum number of lines.
227    pub lines: Optional<I>,
228    /// Whether block-size clamping is applied.
229    #[css(skip_if = "MaxLinesKeyword::is_none")]
230    #[animation(constant)]
231    pub kw: MaxLinesKeyword,
232}
233
234pub use self::GenericMaxLines as MaxLines;
235
236impl<I> MaxLines<I> {
237    /// Returns a new `none` value.
238    pub fn none() -> Self {
239        Self {
240            lines: Optional::None,
241            kw: MaxLinesKeyword::None,
242        }
243    }
244
245    /// Returns a new `auto` value.
246    pub fn auto() -> Self {
247        Self {
248            lines: Optional::None,
249            kw: MaxLinesKeyword::Auto,
250        }
251    }
252
253    /// Returns a new line-count value, optionally with the `auto` keyword.
254    pub fn lines(lines: I, auto: bool) -> Self {
255        Self {
256            lines: Optional::Some(lines),
257            kw: if auto {
258                MaxLinesKeyword::Auto
259            } else {
260                MaxLinesKeyword::None
261            },
262        }
263    }
264
265    /// Returns whether there is no line-count or block-size clamping.
266    pub fn is_none(&self) -> bool {
267        self.lines.is_none() && matches!(self.kw, MaxLinesKeyword::None)
268    }
269
270    /// Returns whether this value is `auto`.
271    pub fn is_auto(&self) -> bool {
272        self.lines.is_none() && matches!(self.kw, MaxLinesKeyword::Auto)
273    }
274
275    /// Returns the line count if exists.
276    pub fn lines_value(&self) -> Option<&I> {
277        self.lines.as_ref()
278    }
279}
280
281/// A generic value for the `line-clamp` property.
282#[derive(
283    Animate,
284    Clone,
285    ComputeSquaredDistance,
286    Debug,
287    MallocSizeOf,
288    PartialEq,
289    SpecifiedValueInfo,
290    ToAnimatedValue,
291    ToAnimatedZero,
292    ToComputedValue,
293    ToResolvedValue,
294    ToShmem,
295    ToTyped,
296)]
297#[repr(C)]
298#[typed(todo_derive_fields)]
299#[value_info(other_values = "none")]
300pub struct GenericLineClamp<I> {
301    /// Maximum `line-count` and `block-size` clamping behavior.
302    pub max_lines: GenericMaxLines<I>,
303    /// Ellipsis displayed at the clamp point.
304    #[animation(constant)]
305    pub block_ellipsis: BlockEllipsis,
306    /// Whether legacy line clamping behavior is used.
307    #[animation(constant)]
308    pub webkit_legacy: bool,
309    /// Whether the `-webkit-legacy` keyword is printed during serialization.
310    #[animation(constant)]
311    pub serialize_webkit_legacy: bool,
312}
313
314pub use self::GenericLineClamp as LineClamp;
315
316impl<I> LineClamp<I> {
317    /// Returns the `none` value.
318    pub fn none() -> Self {
319        Self {
320            max_lines: MaxLines::none(),
321            block_ellipsis: BlockEllipsis::Ellipsis,
322            webkit_legacy: false,
323            serialize_webkit_legacy: false,
324        }
325    }
326
327    /// Returns whether we are the `none` value or not.
328    pub fn is_none(&self) -> bool {
329        self.max_lines.is_none() && self.block_ellipsis.is_ellipsis()
330    }
331}
332
333impl<I: ToCss> ToCss for LineClamp<I> {
334    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
335    where
336        W: Write,
337    {
338        if self.is_none() {
339            return dest.write_str("none");
340        }
341
342        let mut writer = SequenceWriter::new(dest, " ");
343        if !self.max_lines.is_none() {
344            writer.item(&self.max_lines)?;
345        }
346        if !self.block_ellipsis.is_ellipsis() {
347            writer.item(&self.block_ellipsis)?;
348        }
349        if self.webkit_legacy
350            && self.serialize_webkit_legacy
351            && static_prefs::pref!("layout.css.line-clamp.enabled")
352        {
353            writer.raw_item("-webkit-legacy")?;
354        }
355        Ok(())
356    }
357}
358
359/// A generic value for the `perspective` property.
360#[derive(
361    Animate,
362    Clone,
363    ComputeSquaredDistance,
364    Copy,
365    Debug,
366    MallocSizeOf,
367    Parse,
368    PartialEq,
369    SpecifiedValueInfo,
370    ToAnimatedValue,
371    ToAnimatedZero,
372    ToComputedValue,
373    ToCss,
374    ToResolvedValue,
375    ToShmem,
376    ToTyped,
377)]
378#[repr(C, u8)]
379pub enum GenericPerspective<NonNegativeLength> {
380    /// A non-negative length.
381    Length(NonNegativeLength),
382    /// The keyword `none`.
383    None,
384}
385
386pub use self::GenericPerspective as Perspective;
387
388impl<L> Perspective<L> {
389    /// Returns `none`.
390    #[inline]
391    pub fn none() -> Self {
392        Perspective::None
393    }
394}
395
396#[derive(
397    Clone,
398    Copy,
399    Debug,
400    MallocSizeOf,
401    Parse,
402    PartialEq,
403    SpecifiedValueInfo,
404    ToComputedValue,
405    ToCss,
406    ToResolvedValue,
407    ToShmem,
408    ToTyped,
409)]
410#[repr(u8)]
411#[allow(missing_docs)]
412pub enum PositionProperty {
413    Static = 0,
414    Relative,
415    Absolute,
416    Fixed,
417    Sticky,
418}
419
420impl PositionProperty {
421    /// Is the box absolutely positioned?
422    pub fn is_absolutely_positioned(self) -> bool {
423        matches!(self, Self::Absolute | Self::Fixed)
424    }
425}
426
427/// https://drafts.csswg.org/css-overflow-4/#overflow-clip-margin's <visual-box>. Note that the
428/// spec has special behavior for the omitted keyword, but that's rather odd, see:
429/// https://github.com/w3c/csswg-drafts/issues/13185
430#[allow(missing_docs)]
431#[derive(
432    Clone,
433    ComputeSquaredDistance,
434    Copy,
435    Debug,
436    Eq,
437    MallocSizeOf,
438    PartialEq,
439    Parse,
440    SpecifiedValueInfo,
441    ToAnimatedValue,
442    ToComputedValue,
443    ToCss,
444    ToResolvedValue,
445    ToShmem,
446    ToTyped,
447)]
448#[repr(u8)]
449pub enum OverflowClipMarginBox {
450    ContentBox,
451    PaddingBox,
452    BorderBox,
453}
454
455/// https://drafts.csswg.org/css-overflow-4/#overflow-clip-margin
456#[derive(
457    Animate,
458    Clone,
459    ComputeSquaredDistance,
460    Copy,
461    Debug,
462    Eq,
463    MallocSizeOf,
464    PartialEq,
465    SpecifiedValueInfo,
466    ToAnimatedValue,
467    ToComputedValue,
468    ToAnimatedZero,
469    ToResolvedValue,
470    ToShmem,
471    ToTyped,
472)]
473#[repr(C)]
474pub struct GenericOverflowClipMargin<L> {
475    /// The offset of the clip.
476    pub offset: L,
477    /// The box that we're clipping to.
478    #[animation(constant)]
479    pub visual_box: OverflowClipMarginBox,
480}
481
482pub use self::GenericOverflowClipMargin as OverflowClipMargin;
483
484impl<L: Zero> GenericOverflowClipMargin<L> {
485    /// Returns the `none` value.
486    pub fn zero() -> Self {
487        Self {
488            offset: Zero::zero(),
489            visual_box: OverflowClipMarginBox::PaddingBox,
490        }
491    }
492}
493
494impl<L: Zero + ToCss> ToCss for OverflowClipMargin<L> {
495    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
496    where
497        W: Write,
498    {
499        if self.visual_box == OverflowClipMarginBox::PaddingBox {
500            return self.offset.to_css(dest);
501        }
502        self.visual_box.to_css(dest)?;
503        if !self.offset.is_zero() {
504            dest.write_char(' ')?;
505            self.offset.to_css(dest)?;
506        }
507        Ok(())
508    }
509}