style/stylesheets/
layer_rule.rs1use crate::parser::{Parse, ParserContext};
10use crate::shared_lock::{DeepCloneWithLock, Locked};
11use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
12use crate::values::AtomIdent;
13
14use super::CssRules;
15
16use cssparser::{Parser, SourceLocation, Token};
17use servo_arc::Arc;
18use smallvec::SmallVec;
19use std::fmt::{self, Write};
20use style_traits::{CssWriter, ParseError, ToCss};
21
22#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord)]
26pub struct LayerOrder(u16);
27
28impl LayerOrder {
29 pub const fn root() -> Self {
31 Self(std::u16::MAX - 1)
32 }
33
34 pub const fn style_attribute() -> Self {
36 Self(std::u16::MAX)
37 }
38
39 #[inline]
46 pub fn is_style_attribute_layer(&self) -> bool {
47 *self == Self::style_attribute()
48 }
49
50 pub const fn first() -> Self {
52 Self(0)
53 }
54
55 #[inline]
57 pub fn inc(&mut self) {
58 if self.0 != std::u16::MAX - 1 {
59 self.0 += 1;
60 }
61 }
62}
63
64#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
66pub struct LayerName(pub SmallVec<[AtomIdent; 1]>);
67
68impl LayerName {
69 pub fn new_empty() -> Self {
72 Self(Default::default())
73 }
74
75 pub fn new_anonymous() -> Self {
77 use std::sync::atomic::{AtomicUsize, Ordering};
78 static NEXT_ANONYMOUS_LAYER_NAME: AtomicUsize = AtomicUsize::new(0);
79
80 let mut name = SmallVec::new();
81 let next_id = NEXT_ANONYMOUS_LAYER_NAME.fetch_add(1, Ordering::Relaxed);
82 name.push(AtomIdent::from(&*format!("-moz-anon-layer({})", next_id)));
86
87 LayerName(name)
88 }
89
90 pub fn layer_names(&self) -> &[AtomIdent] {
93 &self.0
94 }
95}
96
97impl Parse for LayerName {
98 fn parse<'i, 't>(
99 _: &ParserContext,
100 input: &mut Parser<'i, 't>,
101 ) -> Result<Self, ParseError<'i>> {
102 let mut result = SmallVec::new();
103 result.push(AtomIdent::from(&**input.expect_ident()?));
104 loop {
105 let next_name = input.try_parse(|input| -> Result<AtomIdent, ParseError<'i>> {
106 match input.next_including_whitespace()? {
107 Token::Delim('.') => {},
108 other => {
109 let t = other.clone();
110 return Err(input.new_unexpected_token_error(t));
111 },
112 }
113
114 let name = match input.next_including_whitespace()? {
115 Token::Ident(ref ident) => ident,
116 other => {
117 let t = other.clone();
118 return Err(input.new_unexpected_token_error(t));
119 },
120 };
121
122 Ok(AtomIdent::from(&**name))
123 });
124
125 match next_name {
126 Ok(name) => result.push(name),
127 Err(..) => break,
128 }
129 }
130 Ok(LayerName(result))
131 }
132}
133
134impl ToCss for LayerName {
135 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
136 where
137 W: Write,
138 {
139 let mut first = true;
140 for name in self.0.iter() {
141 if !first {
142 dest.write_char('.')?;
143 }
144 first = false;
145 name.to_css(dest)?;
146 }
147 Ok(())
148 }
149}
150
151#[derive(Debug, ToShmem)]
152pub struct LayerBlockRule {
155 pub name: Option<LayerName>,
157 pub rules: Arc<Locked<CssRules>>,
159 pub source_location: SourceLocation,
161}
162
163impl ToCssWithGuard for LayerBlockRule {
164 fn to_css(
165 &self,
166 guard: &SharedRwLockReadGuard,
167 dest: &mut crate::str::CssStringWriter,
168 ) -> fmt::Result {
169 dest.write_str("@layer")?;
170 if let Some(ref name) = self.name {
171 dest.write_char(' ')?;
172 name.to_css(&mut CssWriter::new(dest))?;
173 }
174 self.rules.read_with(guard).to_css_block(guard, dest)
175 }
176}
177
178impl DeepCloneWithLock for LayerBlockRule {
179 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
180 Self {
181 name: self.name.clone(),
182 rules: Arc::new(
183 lock.wrap(
184 self.rules
185 .read_with(guard)
186 .deep_clone_with_lock(lock, guard),
187 ),
188 ),
189 source_location: self.source_location.clone(),
190 }
191 }
192}
193
194#[derive(Clone, Debug, ToShmem)]
198pub struct LayerStatementRule {
199 pub names: Vec<LayerName>,
201 pub source_location: SourceLocation,
203}
204
205impl ToCssWithGuard for LayerStatementRule {
206 fn to_css(
207 &self,
208 _: &SharedRwLockReadGuard,
209 dest: &mut crate::str::CssStringWriter,
210 ) -> fmt::Result {
211 let mut writer = CssWriter::new(dest);
212 writer.write_str("@layer ")?;
213 let mut first = true;
214 for name in &*self.names {
215 if !first {
216 writer.write_str(", ")?;
217 }
218 first = false;
219 name.to_css(&mut writer)?;
220 }
221 writer.write_char(';')
222 }
223}