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#[inline]
193fn is_decimal(counter_type: &CounterStyle) -> bool {
194    *counter_type == CounterStyle::decimal()
195}
196
197/// The non-normal, non-none values of the content property.
198#[derive(
199    Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToShmem,
200)]
201#[repr(C)]
202pub struct GenericContentItems<Image> {
203    /// The actual content items. Note that, past the alt marker, only some subset (strings,
204    /// attr(), counter())
205    pub items: thin_vec::ThinVec<GenericContentItem<Image>>,
206    /// The index at which alt text starts, always non-zero. If equal to items.len(), no alt text
207    /// exists.
208    pub alt_start: usize,
209}
210
211impl<Image> ToCss for GenericContentItems<Image>
212where
213    Image: ToCss,
214{
215    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
216    where
217        W: Write,
218    {
219        for (i, item) in self.items.iter().enumerate() {
220            if i == self.alt_start {
221                dest.write_str(" /")?;
222            }
223            if i != 0 {
224                dest.write_str(" ")?;
225            }
226            item.to_css(dest)?;
227        }
228        Ok(())
229    }
230}
231
232/// The specified value for the `content` property.
233///
234/// https://drafts.csswg.org/css-content/#propdef-content
235#[derive(
236    Clone,
237    Debug,
238    Eq,
239    MallocSizeOf,
240    PartialEq,
241    SpecifiedValueInfo,
242    ToComputedValue,
243    ToCss,
244    ToShmem,
245    ToTyped,
246)]
247#[repr(u8)]
248#[typed(todo_derive_fields)]
249pub enum GenericContent<Image> {
250    /// `normal` reserved keyword.
251    Normal,
252    /// `none` reserved keyword.
253    None,
254    /// Content items.
255    Items(GenericContentItems<Image>),
256}
257
258pub use self::GenericContent as Content;
259
260impl<Image> Content<Image> {
261    /// Whether `self` represents list of items.
262    #[inline]
263    pub fn is_items(&self) -> bool {
264        matches!(*self, Self::Items(..))
265    }
266
267    /// Set `content` property to `normal`.
268    #[inline]
269    pub fn normal() -> Self {
270        Content::Normal
271    }
272}
273
274/// Items for the `content` property.
275#[derive(
276    Clone,
277    Debug,
278    Eq,
279    MallocSizeOf,
280    PartialEq,
281    ToComputedValue,
282    SpecifiedValueInfo,
283    ToCss,
284    ToResolvedValue,
285    ToShmem,
286)]
287#[repr(u8)]
288pub enum GenericContentItem<I> {
289    /// Literal string content.
290    String(crate::OwnedStr),
291    /// `counter(name, style)`.
292    #[css(comma, function)]
293    Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyle),
294    /// `counters(name, separator, style)`.
295    #[css(comma, function)]
296    Counters(
297        CustomIdent,
298        crate::OwnedStr,
299        #[css(skip_if = "is_decimal")] CounterStyle,
300    ),
301    /// `open-quote`.
302    OpenQuote,
303    /// `close-quote`.
304    CloseQuote,
305    /// `no-open-quote`.
306    NoOpenQuote,
307    /// `no-close-quote`.
308    NoCloseQuote,
309    /// `-moz-alt-content`.
310    #[cfg(feature = "gecko")]
311    MozAltContent,
312    /// `-moz-label-content`.
313    /// This is needed to make `accesskey` work for XUL labels. It's basically
314    /// attr(value) otherwise.
315    #[cfg(feature = "gecko")]
316    MozLabelContent,
317    /// `attr([namespace? `|`]? ident)`
318    Attr(Attr),
319    /// image-set(url) | url(url)
320    Image(I),
321}
322
323pub use self::GenericContentItem as ContentItem;