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)]
76#[repr(transparent)]
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)]
110#[repr(transparent)]
111pub struct GenericCounterSet<I>(#[css(field_bound)] pub GenericCounters<I>);
112pub use self::GenericCounterSet as CounterSet;
113
114impl<I> CounterSet<I> {
115    /// Returns a new value for `counter-set`.
116    #[inline]
117    pub fn new(counters: Vec<CounterPair<I>>) -> Self {
118        CounterSet(Counters(counters.into()))
119    }
120}
121
122impl<I> Deref for CounterSet<I> {
123    type Target = [CounterPair<I>];
124
125    #[inline]
126    fn deref(&self) -> &Self::Target {
127        &(self.0).0
128    }
129}
130
131/// A generic value for the `counter-reset` property.
132#[derive(
133    Clone,
134    Debug,
135    Default,
136    MallocSizeOf,
137    PartialEq,
138    SpecifiedValueInfo,
139    ToComputedValue,
140    ToCss,
141    ToResolvedValue,
142    ToShmem,
143)]
144#[repr(transparent)]
145pub struct GenericCounterReset<I>(#[css(field_bound)] pub GenericCounters<I>);
146pub use self::GenericCounterReset as CounterReset;
147
148impl<I> CounterReset<I> {
149    /// Returns a new value for `counter-reset`.
150    #[inline]
151    pub fn new(counters: Vec<CounterPair<I>>) -> Self {
152        CounterReset(Counters(counters.into()))
153    }
154}
155
156impl<I> Deref for CounterReset<I> {
157    type Target = [CounterPair<I>];
158
159    #[inline]
160    fn deref(&self) -> &Self::Target {
161        &(self.0).0
162    }
163}
164
165/// A generic value for lists of counters.
166///
167/// Keyword `none` is represented by an empty vector.
168#[derive(
169    Clone,
170    Debug,
171    Default,
172    MallocSizeOf,
173    PartialEq,
174    SpecifiedValueInfo,
175    ToComputedValue,
176    ToCss,
177    ToResolvedValue,
178    ToShmem,
179)]
180#[repr(transparent)]
181pub struct GenericCounters<I>(
182    #[css(field_bound)]
183    #[css(iterable, if_empty = "none")]
184    crate::OwnedSlice<GenericCounterPair<I>>,
185);
186pub use self::GenericCounters as Counters;
187
188#[cfg(feature = "servo")]
189type CounterStyleType = ListStyleType;
190
191#[cfg(feature = "gecko")]
192type CounterStyleType = CounterStyle;
193
194#[cfg(feature = "servo")]
195#[inline]
196fn is_decimal(counter_type: &CounterStyleType) -> bool {
197    *counter_type == ListStyleType::Decimal
198}
199
200#[cfg(feature = "gecko")]
201#[inline]
202fn is_decimal(counter_type: &CounterStyleType) -> bool {
203    *counter_type == CounterStyle::decimal()
204}
205
206/// The non-normal, non-none values of the content property.
207#[derive(
208    Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToShmem,
209)]
210#[repr(C)]
211pub struct GenericContentItems<Image> {
212    /// The actual content items. Note that, past the alt marker, only some subset (strings,
213    /// attr(), counter())
214    pub items: thin_vec::ThinVec<GenericContentItem<Image>>,
215    /// The index at which alt text starts, always non-zero. If equal to items.len(), no alt text
216    /// exists.
217    pub alt_start: usize,
218}
219
220impl<Image> ToCss for GenericContentItems<Image>
221where
222    Image: ToCss,
223{
224    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
225    where
226        W: Write,
227    {
228        for (i, item) in self.items.iter().enumerate() {
229            if i == self.alt_start {
230                dest.write_str(" /")?;
231            }
232            if i != 0 {
233                dest.write_str(" ")?;
234            }
235            item.to_css(dest)?;
236        }
237        Ok(())
238    }
239}
240
241/// The specified value for the `content` property.
242///
243/// https://drafts.csswg.org/css-content/#propdef-content
244#[derive(
245    Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToShmem,
246)]
247#[repr(u8)]
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")] CounterStyleType),
293    /// `counters(name, separator, style)`.
294    #[css(comma, function)]
295    Counters(
296        CustomIdent,
297        crate::OwnedStr,
298        #[css(skip_if = "is_decimal")] CounterStyleType,
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    /// `attr([namespace? `|`]? ident)`
317    Attr(Attr),
318    /// image-set(url) | url(url)
319    Image(I),
320}
321
322pub use self::GenericContentItem as ContentItem;