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