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