style/stylesheets/
import_rule.rs1use crate::media_queries::MediaList;
10use crate::parser::{Parse, ParserContext};
11use crate::shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
12use crate::str::CssStringWriter;
13use crate::stylesheets::{
14 layer_rule::LayerName, supports_rule::SupportsCondition, CssRule, CssRuleType,
15 StylesheetInDocument,
16};
17use crate::values::CssUrl;
18use cssparser::{Parser, SourceLocation};
19use std::fmt::{self, Write};
20use style_traits::{CssWriter, ToCss};
21use to_shmem::{SharedMemoryBuilder, ToShmem};
22
23#[cfg(feature = "gecko")]
25#[derive(Debug)]
26pub enum ImportSheet {
27 Sheet(crate::gecko::data::GeckoStyleSheet),
29
30 Pending,
33
34 Refused,
36}
37
38#[cfg(feature = "gecko")]
39impl ImportSheet {
40 pub fn new(sheet: crate::gecko::data::GeckoStyleSheet) -> Self {
42 ImportSheet::Sheet(sheet)
43 }
44
45 pub fn new_pending() -> Self {
47 ImportSheet::Pending
48 }
49
50 pub fn new_refused() -> Self {
52 ImportSheet::Refused
53 }
54
55 pub fn as_sheet(&self) -> Option<&crate::gecko::data::GeckoStyleSheet> {
58 match *self {
59 ImportSheet::Sheet(ref s) => {
60 debug_assert!(!s.hack_is_null());
61 if s.hack_is_null() {
62 return None;
63 }
64 Some(s)
65 },
66 ImportSheet::Refused | ImportSheet::Pending => None,
67 }
68 }
69
70 pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
72 self.as_sheet().and_then(|s| s.media(guard))
73 }
74
75 pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
77 match self.as_sheet() {
78 Some(s) => s.rules(guard),
79 None => &[],
80 }
81 }
82}
83
84#[cfg(feature = "gecko")]
85impl DeepCloneWithLock for ImportSheet {
86 fn deep_clone_with_lock(&self, _lock: &SharedRwLock, _guard: &SharedRwLockReadGuard) -> Self {
87 use crate::gecko::data::GeckoStyleSheet;
88 use crate::gecko_bindings::bindings;
89 match *self {
90 ImportSheet::Sheet(ref s) => {
91 let clone = unsafe { bindings::Gecko_StyleSheet_Clone(s.raw() as *const _) };
92 ImportSheet::Sheet(unsafe { GeckoStyleSheet::from_addrefed(clone) })
93 },
94 ImportSheet::Pending => ImportSheet::Pending,
95 ImportSheet::Refused => ImportSheet::Refused,
96 }
97 }
98}
99
100#[cfg(feature = "servo")]
102#[derive(Debug)]
103pub enum ImportSheet {
104 Sheet(::servo_arc::Arc<crate::stylesheets::Stylesheet>),
106
107 Refused,
109}
110
111#[cfg(feature = "servo")]
112impl ImportSheet {
113 pub fn new(sheet: ::servo_arc::Arc<crate::stylesheets::Stylesheet>) -> Self {
115 ImportSheet::Sheet(sheet)
116 }
117
118 pub fn new_refused() -> Self {
120 ImportSheet::Refused
121 }
122
123 pub fn as_sheet(&self) -> Option<&::servo_arc::Arc<crate::stylesheets::Stylesheet>> {
125 match *self {
126 ImportSheet::Sheet(ref s) => Some(s),
127 ImportSheet::Refused => None,
128 }
129 }
130
131 pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
133 self.as_sheet().and_then(|s| s.media(guard))
134 }
135
136 pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
138 match self.as_sheet() {
139 Some(s) => s.rules(guard),
140 None => &[],
141 }
142 }
143}
144
145#[cfg(feature = "servo")]
146impl DeepCloneWithLock for ImportSheet {
147 fn deep_clone_with_lock(&self, _lock: &SharedRwLock, _guard: &SharedRwLockReadGuard) -> Self {
148 match *self {
149 ImportSheet::Sheet(ref s) => {
150 use servo_arc::Arc;
151 ImportSheet::Sheet(Arc::new((&**s).clone()))
152 },
153 ImportSheet::Refused => ImportSheet::Refused,
154 }
155 }
156}
157
158#[derive(Debug, Clone)]
160pub enum ImportLayer {
161 None,
163
164 Anonymous,
166
167 Named(LayerName),
169}
170
171#[derive(Debug, Clone)]
173pub struct ImportSupportsCondition {
174 pub condition: SupportsCondition,
176
177 pub enabled: bool,
179}
180
181impl ToCss for ImportLayer {
182 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
183 where
184 W: Write,
185 {
186 match *self {
187 ImportLayer::None => Ok(()),
188 ImportLayer::Anonymous => dest.write_str("layer"),
189 ImportLayer::Named(ref name) => {
190 dest.write_str("layer(")?;
191 name.to_css(dest)?;
192 dest.write_char(')')
193 },
194 }
195 }
196}
197
198#[derive(Debug)]
202pub struct ImportRule {
203 pub url: CssUrl,
205
206 pub stylesheet: ImportSheet,
210
211 pub supports: Option<ImportSupportsCondition>,
213
214 pub layer: ImportLayer,
216
217 pub source_location: SourceLocation,
219}
220
221impl ImportRule {
222 pub fn parse_layer_and_supports<'i, 't>(
231 input: &mut Parser<'i, 't>,
232 context: &mut ParserContext,
233 ) -> (ImportLayer, Option<ImportSupportsCondition>) {
234 let layer = if input
235 .try_parse(|input| input.expect_ident_matching("layer"))
236 .is_ok()
237 {
238 ImportLayer::Anonymous
239 } else {
240 input
241 .try_parse(|input| {
242 input.expect_function_matching("layer")?;
243 input
244 .parse_nested_block(|input| LayerName::parse(context, input))
245 .map(|name| ImportLayer::Named(name))
246 })
247 .ok()
248 .unwrap_or(ImportLayer::None)
249 };
250
251 let supports = input
252 .try_parse(SupportsCondition::parse_for_import)
253 .map(|condition| {
254 let enabled =
255 context.nest_for_rule(CssRuleType::Style, |context| condition.eval(context));
256 ImportSupportsCondition { condition, enabled }
257 })
258 .ok();
259
260 (layer, supports)
261 }
262}
263
264impl ToShmem for ImportRule {
265 fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
266 Err(String::from(
267 "ToShmem failed for ImportRule: cannot handle imported style sheets",
268 ))
269 }
270}
271
272impl DeepCloneWithLock for ImportRule {
273 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
274 ImportRule {
275 url: self.url.clone(),
276 stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard),
277 supports: self.supports.clone(),
278 layer: self.layer.clone(),
279 source_location: self.source_location.clone(),
280 }
281 }
282}
283
284impl ToCssWithGuard for ImportRule {
285 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
286 dest.write_str("@import ")?;
287 self.url.to_css(&mut CssWriter::new(dest))?;
288
289 if !matches!(self.layer, ImportLayer::None) {
290 dest.write_char(' ')?;
291 self.layer.to_css(&mut CssWriter::new(dest))?;
292 }
293
294 if let Some(ref supports) = self.supports {
295 dest.write_str(" supports(")?;
296 supports.condition.to_css(&mut CssWriter::new(dest))?;
297 dest.write_char(')')?;
298 }
299
300 if let Some(media) = self.stylesheet.media(guard) {
301 if !media.is_empty() {
302 dest.write_char(' ')?;
303 media.to_css(&mut CssWriter::new(dest))?;
304 }
305 }
306
307 dest.write_char(';')
308 }
309}