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