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