style/stylesheets/
import_rule.rs1use crate::media_queries::MediaList;
10use crate::parser::{Parse, ParserContext};
11use crate::shared_lock::{
12 DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
13};
14use crate::str::CssStringWriter;
15use crate::stylesheets::{
16 layer_rule::LayerName, supports_rule::SupportsCondition, CssRule, CssRuleType,
17 StylesheetInDocument,
18};
19use crate::values::CssUrl;
20use cssparser::{Parser, SourceLocation};
21use std::fmt::{self, Write};
22use style_traits::{CssWriter, ToCss};
23use to_shmem::{SharedMemoryBuilder, ToShmem};
24
25#[cfg(feature = "gecko")]
27#[derive(Debug)]
28pub enum ImportSheet {
29 Sheet(crate::gecko::data::GeckoStyleSheet),
31
32 Pending,
35
36 Refused,
38}
39
40#[cfg(feature = "gecko")]
41impl ImportSheet {
42 pub fn new(sheet: crate::gecko::data::GeckoStyleSheet) -> Self {
44 ImportSheet::Sheet(sheet)
45 }
46
47 pub fn new_pending() -> Self {
49 ImportSheet::Pending
50 }
51
52 pub fn new_refused() -> Self {
54 ImportSheet::Refused
55 }
56
57 pub fn as_sheet(&self) -> Option<&crate::gecko::data::GeckoStyleSheet> {
60 match *self {
61 ImportSheet::Sheet(ref s) => {
62 debug_assert!(!s.hack_is_null());
63 if s.hack_is_null() {
64 return None;
65 }
66 Some(s)
67 },
68 ImportSheet::Refused | ImportSheet::Pending => None,
69 }
70 }
71
72 pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
74 self.as_sheet().and_then(|s| s.media(guard))
75 }
76
77 pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
79 match self.as_sheet() {
80 Some(s) => s.rules(guard),
81 None => &[],
82 }
83 }
84}
85
86#[cfg(feature = "gecko")]
87impl DeepCloneWithLock for ImportSheet {
88 fn deep_clone_with_lock(
89 &self,
90 _lock: &SharedRwLock,
91 _guard: &SharedRwLockReadGuard,
92 ) -> Self {
93 use crate::gecko::data::GeckoStyleSheet;
94 use crate::gecko_bindings::bindings;
95 match *self {
96 ImportSheet::Sheet(ref s) => {
97 let clone = unsafe {
98 bindings::Gecko_StyleSheet_Clone(s.raw() as *const _)
99 };
100 ImportSheet::Sheet(unsafe { GeckoStyleSheet::from_addrefed(clone) })
101 },
102 ImportSheet::Pending => ImportSheet::Pending,
103 ImportSheet::Refused => ImportSheet::Refused,
104 }
105 }
106}
107
108#[cfg(feature = "servo")]
110#[derive(Debug)]
111pub enum ImportSheet {
112 Sheet(::servo_arc::Arc<crate::stylesheets::Stylesheet>),
114
115 Refused,
117}
118
119#[cfg(feature = "servo")]
120impl ImportSheet {
121 pub fn new(sheet: ::servo_arc::Arc<crate::stylesheets::Stylesheet>) -> Self {
123 ImportSheet::Sheet(sheet)
124 }
125
126 pub fn new_refused() -> Self {
128 ImportSheet::Refused
129 }
130
131 pub fn as_sheet(&self) -> Option<&::servo_arc::Arc<crate::stylesheets::Stylesheet>> {
133 match *self {
134 ImportSheet::Sheet(ref s) => Some(s),
135 ImportSheet::Refused => None,
136 }
137 }
138
139 pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
141 self.as_sheet().and_then(|s| s.media(guard))
142 }
143
144 pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
146 match self.as_sheet() {
147 Some(s) => s.rules(guard),
148 None => &[],
149 }
150 }
151}
152
153#[cfg(feature = "servo")]
154impl DeepCloneWithLock for ImportSheet {
155 fn deep_clone_with_lock(
156 &self,
157 _lock: &SharedRwLock,
158 _guard: &SharedRwLockReadGuard,
159 ) -> Self {
160 match *self {
161 ImportSheet::Sheet(ref s) => {
162 use servo_arc::Arc;
163 ImportSheet::Sheet(Arc::new((&**s).clone()))
164 },
165 ImportSheet::Refused => ImportSheet::Refused,
166 }
167 }
168}
169
170#[derive(Debug, Clone)]
172pub enum ImportLayer {
173 None,
175
176 Anonymous,
178
179 Named(LayerName),
181}
182
183#[derive(Debug, Clone)]
185pub struct ImportSupportsCondition {
186 pub condition: SupportsCondition,
188
189 pub enabled: bool,
191}
192
193impl ToCss for ImportLayer {
194 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
195 where
196 W: Write,
197 {
198 match *self {
199 ImportLayer::None => Ok(()),
200 ImportLayer::Anonymous => dest.write_str("layer"),
201 ImportLayer::Named(ref name) => {
202 dest.write_str("layer(")?;
203 name.to_css(dest)?;
204 dest.write_char(')')
205 },
206 }
207 }
208}
209
210#[derive(Debug)]
214pub struct ImportRule {
215 pub url: CssUrl,
217
218 pub stylesheet: ImportSheet,
222
223 pub supports: Option<ImportSupportsCondition>,
225
226 pub layer: ImportLayer,
228
229 pub source_location: SourceLocation,
231}
232
233impl ImportRule {
234 pub fn parse_layer_and_supports<'i, 't>(
243 input: &mut Parser<'i, 't>,
244 context: &mut ParserContext,
245 ) -> (ImportLayer, Option<ImportSupportsCondition>) {
246 let layer = if input
247 .try_parse(|input| input.expect_ident_matching("layer"))
248 .is_ok()
249 {
250 ImportLayer::Anonymous
251 } else {
252 input
253 .try_parse(|input| {
254 input.expect_function_matching("layer")?;
255 input
256 .parse_nested_block(|input| LayerName::parse(context, input))
257 .map(|name| ImportLayer::Named(name))
258 })
259 .ok()
260 .unwrap_or(ImportLayer::None)
261 };
262
263 let supports = if !static_prefs::pref!("layout.css.import-supports.enabled") {
264 None
265 } else {
266 input
267 .try_parse(SupportsCondition::parse_for_import)
268 .map(|condition| {
269 let enabled = context
270 .nest_for_rule(CssRuleType::Style, |context| condition.eval(context));
271 ImportSupportsCondition { condition, enabled }
272 })
273 .ok()
274 };
275
276 (layer, supports)
277 }
278}
279
280impl ToShmem for ImportRule {
281 fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
282 Err(String::from(
283 "ToShmem failed for ImportRule: cannot handle imported style sheets",
284 ))
285 }
286}
287
288impl DeepCloneWithLock for ImportRule {
289 fn deep_clone_with_lock(
290 &self,
291 lock: &SharedRwLock,
292 guard: &SharedRwLockReadGuard,
293 ) -> Self {
294 ImportRule {
295 url: self.url.clone(),
296 stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard),
297 supports: self.supports.clone(),
298 layer: self.layer.clone(),
299 source_location: self.source_location.clone(),
300 }
301 }
302}
303
304impl ToCssWithGuard for ImportRule {
305 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
306 dest.write_str("@import ")?;
307 self.url.to_css(&mut CssWriter::new(dest))?;
308
309 if !matches!(self.layer, ImportLayer::None) {
310 dest.write_char(' ')?;
311 self.layer.to_css(&mut CssWriter::new(dest))?;
312 }
313
314 if let Some(ref supports) = self.supports {
315 dest.write_str(" supports(")?;
316 supports.condition.to_css(&mut CssWriter::new(dest))?;
317 dest.write_char(')')?;
318 }
319
320 if let Some(media) = self.stylesheet.media(guard) {
321 if !media.is_empty() {
322 dest.write_char(' ')?;
323 media.to_css(&mut CssWriter::new(dest))?;
324 }
325 }
326
327 dest.write_char(';')
328 }
329}