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}
310
311pub use self::GenericLineClamp as LineClamp;
312
313impl<I> LineClamp<I> {
314    /// Returns the `none` value.
315    pub fn none() -> Self {
316        Self {
317            max_lines: MaxLines::none(),
318            block_ellipsis: BlockEllipsis::Ellipsis,
319            webkit_legacy: false,
320        }
321    }
322
323    /// Returns whether we are the `none` value or not.
324    pub fn is_none(&self) -> bool {
325        self.max_lines.is_none() && self.block_ellipsis.is_ellipsis()
326    }
327}
328
329impl<I: ToCss> ToCss for LineClamp<I> {
330    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
331    where
332        W: Write,
333    {
334        if self.is_none() {
335            return dest.write_str("none");
336        }
337
338        let mut writer = SequenceWriter::new(dest, " ");
339        if !self.max_lines.is_none() {
340            writer.item(&self.max_lines)?;
341        }
342        if !self.block_ellipsis.is_ellipsis() {
343            writer.item(&self.block_ellipsis)?;
344        }
345        if self.webkit_legacy && crate::pref!("layout.css.line-clamp.enabled") {
346            writer.raw_item("-webkit-legacy")?;
347        }
348        Ok(())
349    }
350}
351
352/// A generic value for the `perspective` property.
353#[derive(
354    Animate,
355    Clone,
356    ComputeSquaredDistance,
357    Copy,
358    Debug,
359    MallocSizeOf,
360    Parse,
361    PartialEq,
362    SpecifiedValueInfo,
363    ToAnimatedValue,
364    ToAnimatedZero,
365    ToComputedValue,
366    ToCss,
367    ToResolvedValue,
368    ToShmem,
369    ToTyped,
370)]
371#[repr(C, u8)]
372pub enum GenericPerspective<NonNegativeLength> {
373    /// A non-negative length.
374    Length(NonNegativeLength),
375    /// The keyword `none`.
376    None,
377}
378
379pub use self::GenericPerspective as Perspective;
380
381impl<L> Perspective<L> {
382    /// Returns `none`.
383    #[inline]
384    pub fn none() -> Self {
385        Perspective::None
386    }
387}
388
389#[derive(
390    Clone,
391    Copy,
392    Debug,
393    MallocSizeOf,
394    Parse,
395    PartialEq,
396    SpecifiedValueInfo,
397    ToComputedValue,
398    ToCss,
399    ToResolvedValue,
400    ToShmem,
401    ToTyped,
402)]
403#[repr(u8)]
404#[allow(missing_docs)]
405pub enum PositionProperty {
406    Static = 0,
407    Relative,
408    Absolute,
409    Fixed,
410    Sticky,
411}
412
413impl PositionProperty {
414    /// Is the box absolutely positioned?
415    pub fn is_absolutely_positioned(self) -> bool {
416        matches!(self, Self::Absolute | Self::Fixed)
417    }
418}
419
420/// https://drafts.csswg.org/css-overflow-4/#overflow-clip-margin's <visual-box>. Note that the
421/// spec has special behavior for the omitted keyword, but that's rather odd, see:
422/// https://github.com/w3c/csswg-drafts/issues/13185
423#[allow(missing_docs)]
424#[derive(
425    Clone,
426    ComputeSquaredDistance,
427    Copy,
428    Debug,
429    Eq,
430    MallocSizeOf,
431    PartialEq,
432    Parse,
433    SpecifiedValueInfo,
434    ToAnimatedValue,
435    ToComputedValue,
436    ToCss,
437    ToResolvedValue,
438    ToShmem,
439    ToTyped,
440)]
441#[repr(u8)]
442pub enum OverflowClipMarginBox {
443    ContentBox,
444    PaddingBox,
445    BorderBox,
446}
447
448/// https://drafts.csswg.org/css-overflow-4/#overflow-clip-margin
449#[derive(
450    Animate,
451    Clone,
452    ComputeSquaredDistance,
453    Copy,
454    Debug,
455    Eq,
456    MallocSizeOf,
457    PartialEq,
458    SpecifiedValueInfo,
459    ToAnimatedValue,
460    ToComputedValue,
461    ToAnimatedZero,
462    ToResolvedValue,
463    ToShmem,
464    ToTyped,
465)]
466#[repr(C)]
467pub struct GenericOverflowClipMargin<L> {
468    /// The offset of the clip.
469    pub offset: L,
470    /// The box that we're clipping to.
471    #[animation(constant)]
472    pub visual_box: OverflowClipMarginBox,
473}
474
475pub use self::GenericOverflowClipMargin as OverflowClipMargin;
476
477impl<L: Zero> GenericOverflowClipMargin<L> {
478    /// Returns the `none` value.
479    pub fn zero() -> Self {
480        Self {
481            offset: Zero::zero(),
482            visual_box: OverflowClipMarginBox::PaddingBox,
483        }
484    }
485}
486
487impl<L: Zero + ToCss> ToCss for OverflowClipMargin<L> {
488    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
489    where
490        W: Write,
491    {
492        if self.visual_box == OverflowClipMarginBox::PaddingBox {
493            return self.offset.to_css(dest);
494        }
495        self.visual_box.to_css(dest)?;
496        if !self.offset.is_zero() {
497            dest.write_char(' ')?;
498            self.offset.to_css(dest)?;
499        }
500        Ok(())
501    }
502}
503
504/// The two insets of one scrollbar, for the chrome-only
505/// `-moz-scrollbar-inset-block` / `-moz-scrollbar-inset-inline`. Each property
506/// names the axis the scrollbar runs along, so `start` and `end` are the logical
507/// start and end of that axis and flip with the writing mode.
508#[derive(
509    Clone,
510    Copy,
511    Debug,
512    MallocSizeOf,
513    PartialEq,
514    SpecifiedValueInfo,
515    ToComputedValue,
516    ToResolvedValue,
517    ToShmem,
518    ToTyped,
519)]
520#[repr(C)]
521pub struct GenericScrollbarInset<L> {
522    /// The inset at the logical start of the axis.
523    pub start: L,
524    /// The inset at the logical end of the axis.
525    pub end: L,
526}
527
528pub use self::GenericScrollbarInset as ScrollbarInset;
529
530impl<L: Zero> ScrollbarInset<L> {
531    /// Returns the initial, all-zero value.
532    pub fn zero() -> Self {
533        Self {
534            start: Zero::zero(),
535            end: Zero::zero(),
536        }
537    }
538}
539
540impl<L: PartialEq + ToCss> ToCss for ScrollbarInset<L> {
541    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
542    where
543        W: Write,
544    {
545        self.start.to_css(dest)?;
546        if self.end != self.start {
547            dest.write_char(' ')?;
548            self.end.to_css(dest)?;
549        }
550        Ok(())
551    }
552}