Skip to main content

style/values/generics/
counters.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 counters-related CSS values.
6
7use crate::counter_style::CounterStyle;
8use crate::derives::*;
9use crate::values::CustomIdent;
10use std::fmt::{self, Write};
11use std::ops::Deref;
12use style_traits::{CssWriter, ToCss};
13
14/// A name / value pair for counters.
15#[derive(
16    Clone,
17    Debug,
18    MallocSizeOf,
19    PartialEq,
20    SpecifiedValueInfo,
21    ToComputedValue,
22    ToResolvedValue,
23    ToShmem,
24)]
25#[repr(C)]
26pub struct GenericCounterPair<Integer> {
27    /// The name of the counter.
28    pub name: CustomIdent,
29    /// The value of the counter / increment / etc.
30    pub value: Integer,
31    /// If true, then this represents `reversed(name)`.
32    /// NOTE: It can only be true on `counter-reset` values.
33    pub is_reversed: bool,
34}
35pub use self::GenericCounterPair as CounterPair;
36
37impl<Integer> ToCss for CounterPair<Integer>
38where
39    Integer: ToCss + PartialEq<i32>,
40{
41    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
42    where
43        W: Write,
44    {
45        if self.is_reversed {
46            dest.write_str("reversed(")?;
47        }
48        self.name.to_css(dest)?;
49        if self.is_reversed {
50            dest.write_char(')')?;
51            if self.value == i32::MIN {
52                return Ok(());
53            }
54        }
55        dest.write_char(' ')?;
56        self.value.to_css(dest)
57    }
58}
59
60/// A generic value for the `counter-increment` property.
61#[derive(
62    Clone,
63    Debug,
64    Default,
65    MallocSizeOf,
66    PartialEq,
67    SpecifiedValueInfo,
68    ToComputedValue,
69    ToCss,
70    ToResolvedValue,
71    ToShmem,
72    ToTyped,
73)]
74#[repr(transparent)]
75#[typed(todo_derive_fields)]
76pub struct GenericCounterIncrement<I>(#[css(field_bound)] pub GenericCounters<I>);
77pub use self::GenericCounterIncrement as CounterIncrement;
78
79impl<I> CounterIncrement<I> {
80    /// Returns a new value for `counter-increment`.
81    #[inline]
82    pub fn new(counters: Vec<CounterPair<I>>) -> Self {
83        CounterIncrement(Counters(counters.into()))
84    }
85}
86
87impl<I> Deref for CounterIncrement<I> {
88    type Target = [CounterPair<I>];
89
90    #[inline]
91    fn deref(&self) -> &Self::Target {
92        &(self.0).0
93    }
94}
95
96/// A generic value for the `counter-set` property.
97#[derive(
98    Clone,
99    Debug,
100    Default,
101    MallocSizeOf,
102    PartialEq,
103    SpecifiedValueInfo,
104    ToComputedValue,
105    ToCss,
106    ToResolvedValue,
107    ToShmem,
108    ToTyped,
109)]
110#[repr(transparent)]
111#[typed(todo_derive_fields)]
112pub struct GenericCounterSet<I>(#[css(field_bound)] pub GenericCounters<I>);
113pub use self::GenericCounterSet as CounterSet;
114
115impl<I> CounterSet<I> {
116    /// Returns a new value for `counter-set`.
117    #[inline]
118    pub fn new(counters: Vec<CounterPair<I>>) -> Self {
119        CounterSet(Counters(counters.into()))
120    }
121}
122
123impl<I> Deref for CounterSet<I> {
124    type Target = [CounterPair<I>];
125
126    #[inline]
127    fn deref(&self) -> &Self::Target {
128        &(self.0).0
129    }
130}
131
132/// A generic value for the `counter-reset` property.
133#[derive(
134    Clone,
135    Debug,
136    Default,
137    MallocSizeOf,
138    PartialEq,
139    SpecifiedValueInfo,
140    ToComputedValue,
141    ToCss,
142    ToResolvedValue,
143    ToShmem,
144    ToTyped,
145)]
146#[repr(transparent)]
147#[typed(todo_derive_fields)]
148pub struct GenericCounterReset<I>(#[css(field_bound)] pub GenericCounters<I>);
149pub use self::GenericCounterReset as CounterReset;
150
151impl<I> CounterReset<I> {
152    /// Returns a new value for `counter-reset`.
153    #[inline]
154    pub fn new(counters: Vec<CounterPair<I>>) -> Self {
155        CounterReset(Counters(counters.into()))
156    }
157}
158
159impl<I> Deref for CounterReset<I> {
160    type Target = [CounterPair<I>];
161
162    #[inline]
163    fn deref(&self) -> &Self::Target {
164        &(self.0).0
165    }
166}
167
168/// A generic value for lists of counters.
169///
170/// Keyword `none` is represented by an empty vector.
171#[derive(
172    Clone,
173    Debug,
174    Default,
175    MallocSizeOf,
176    PartialEq,
177    SpecifiedValueInfo,
178    ToComputedValue,
179    ToCss,
180    ToResolvedValue,
181    ToShmem,
182)]
183#[repr(transparent)]
184pub struct GenericCounters<I>(
185    #[css(field_bound)]
186    #[css(iterable, if_empty = "none")]
187    crate::OwnedSlice<GenericCounterPair<I>>,
188);
189pub use self::GenericCounters as Counters;
190
191#[inline]
192fn is_decimal(counter_type: &CounterStyle) -> bool {
193    *counter_type == CounterStyle::decimal()
194}
195
196/// The non-normal, non-none values of the content property.
197#[derive(
198    Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToShmem,
199)]
200#[repr(C)]
201pub struct GenericContentItems<Image> {
202    /// The actual content items. Note that, past the alt marker, only some subset (strings,
203    /// attr(), counter())
204    pub items: thin_vec::ThinVec<GenericContentItem<Image>>,
205    /// The index at which alt text starts, always non-zero. If equal to items.len(), no alt text
206    /// exists.
207    pub alt_start: usize,
208}
209
210impl<Image> ToCss for GenericContentItems<Image>
211where
212    Image: ToCss,
213{
214    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
215    where
216        W: Write,
217    {
218        for (i, item) in self.items.iter().enumerate() {
219            if i == self.alt_start {
220                dest.write_str(" /")?;
221            }
222            if i != 0 {
223                dest.write_str(" ")?;
224            }
225            item.to_css(dest)?;
226        }
227        Ok(())
228    }
229}
230
231/// The specified value for the `content` property.
232///
233/// https://drafts.csswg.org/css-content/#propdef-content
234#[derive(
235    Clone,
236    Debug,
237    Eq,
238    MallocSizeOf,
239    PartialEq,
240    SpecifiedValueInfo,
241    ToComputedValue,
242    ToCss,
243    ToShmem,
244    ToTyped,
245)]
246#[repr(u8)]
247#[typed(todo_derive_fields)]
248pub enum GenericContent<Image> {
249    /// `normal` reserved keyword.
250    Normal,
251    /// `none` reserved keyword.
252    None,
253    /// Content items.
254    Items(GenericContentItems<Image>),
255}
256
257pub use self::GenericContent as Content;
258
259impl<Image> Content<Image> {
260    /// Whether `self` represents list of items.
261    #[inline]
262    pub fn is_items(&self) -> bool {
263        matches!(*self, Self::Items(..))
264    }
265
266    /// Set `content` property to `normal`.
267    #[inline]
268    pub fn normal() -> Self {
269        Content::Normal
270    }
271}
272
273/// Items for the `content` property.
274#[derive(
275    Clone,
276    Debug,
277    Eq,
278    MallocSizeOf,
279    PartialEq,
280    ToComputedValue,
281    SpecifiedValueInfo,
282    ToCss,
283    ToResolvedValue,
284    ToShmem,
285)]
286#[repr(u8)]
287pub enum GenericContentItem<I> {
288    /// Literal string content.
289    String(crate::OwnedStr),
290    /// `counter(name, style)`.
291    #[css(comma, function)]
292    Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyle),
293    /// `counters(name, separator, style)`.
294    #[css(comma, function)]
295    Counters(
296        CustomIdent,
297        crate::OwnedStr,
298        #[css(skip_if = "is_decimal")] CounterStyle,
299    ),
300    /// `open-quote`.
301    OpenQuote,
302    /// `close-quote`.
303    CloseQuote,
304    /// `no-open-quote`.
305    NoOpenQuote,
306    /// `no-close-quote`.
307    NoCloseQuote,
308    /// `-moz-alt-content`.
309    #[cfg(feature = "gecko")]
310    MozAltContent,
311    /// `-moz-label-content`.
312    /// This is needed to make `accesskey` work for XUL labels. It's basically
313    /// attr(value) otherwise.
314    #[cfg(feature = "gecko")]
315    MozLabelContent,
316    /// image-set(url) | url(url)
317    Image(I),
318}
319
320pub use self::GenericContentItem as ContentItem;