1use crate::applicable_declarations::ScopeProximity;
10use crate::dom::TElement;
11use crate::parser::ParserContext;
12use crate::selector_parser::{SelectorImpl, SelectorParser};
13use crate::shared_lock::{
14 DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
15};
16use crate::str::CssStringWriter;
17use crate::stylesheets::CssRules;
18use crate::simple_buckets_map::SimpleBucketsMap;
19use cssparser::{Parser, SourceLocation, ToCss};
20#[cfg(feature = "gecko")]
21use malloc_size_of::{
22 MallocSizeOfOps, MallocUnconditionalShallowSizeOf, MallocUnconditionalSizeOf,
23};
24use selectors::context::{MatchingContext, QuirksMode};
25use selectors::matching::matches_selector;
26use selectors::parser::{Component, ParseRelative, Selector, SelectorList};
27use selectors::OpaqueElement;
28use servo_arc::Arc;
29use std::fmt::{self, Write};
30use style_traits::{CssWriter, ParseError};
31
32#[derive(Debug, ToShmem)]
34pub struct ScopeRule {
35 pub bounds: ScopeBounds,
37 pub rules: Arc<Locked<CssRules>>,
39 pub source_location: SourceLocation,
41}
42
43impl DeepCloneWithLock for ScopeRule {
44 fn deep_clone_with_lock(
45 &self,
46 lock: &SharedRwLock,
47 guard: &SharedRwLockReadGuard,
48 ) -> Self {
49 let rules = self.rules.read_with(guard);
50 Self {
51 bounds: self.bounds.clone(),
52 rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard))),
53 source_location: self.source_location.clone(),
54 }
55 }
56}
57
58impl ToCssWithGuard for ScopeRule {
59 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
60 dest.write_str("@scope")?;
61 {
62 let mut writer = CssWriter::new(dest);
63 if let Some(start) = self.bounds.start.as_ref() {
64 writer.write_str(" (")?;
65 start.to_css(&mut writer)?;
66 writer.write_char(')')?;
67 }
68 if let Some(end) = self.bounds.end.as_ref() {
69 writer.write_str(" to (")?;
70 end.to_css(&mut writer)?;
71 writer.write_char(')')?;
72 }
73 }
74 self.rules.read_with(guard).to_css_block(guard, dest)
75 }
76}
77
78impl ScopeRule {
79 #[cfg(feature = "gecko")]
81 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
82 self.rules.unconditional_shallow_size_of(ops) +
83 self.rules.read_with(guard).size_of(guard, ops) +
84 self.bounds.size_of(ops)
85 }
86}
87
88#[derive(Debug, Clone, ToShmem)]
90pub struct ScopeBounds {
91 pub start: Option<SelectorList<SelectorImpl>>,
93 pub end: Option<SelectorList<SelectorImpl>>,
95}
96
97impl ScopeBounds {
98 #[cfg(feature = "gecko")]
99 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
100 fn bound_size_of(
101 bound: &Option<SelectorList<SelectorImpl>>,
102 ops: &mut MallocSizeOfOps,
103 ) -> usize {
104 bound
105 .as_ref()
106 .map(|list| list.unconditional_size_of(ops))
107 .unwrap_or(0)
108 }
109 bound_size_of(&self.start, ops) + bound_size_of(&self.end, ops)
110 }
111}
112
113fn parse_scope<'a>(
114 context: &ParserContext,
115 input: &mut Parser<'a, '_>,
116 parse_relative: ParseRelative,
117 for_end: bool,
118) -> Result<Option<SelectorList<SelectorImpl>>, ParseError<'a>> {
119 input
120 .try_parse(|input| {
121 if for_end {
122 if input.try_parse(|i| i.expect_ident_matching("to")).is_err() {
124 return Ok(None);
125 }
126 }
127 let parens = input.try_parse(|i| i.expect_parenthesis_block());
128 if for_end {
129 parens?;
131 } else if parens.is_err() {
132 return Ok(None);
134 }
135 input.parse_nested_block(|input| {
136 if input.is_exhausted() {
137 return Ok(None);
139 }
140 let selector_parser = SelectorParser {
141 stylesheet_origin: context.stylesheet_origin,
142 namespaces: &context.namespaces,
143 url_data: context.url_data,
144 for_supports_rule: false,
145 };
146 let parse_relative = if for_end {
147 ParseRelative::ForScope
148 } else {
149 parse_relative
150 };
151 Ok(Some(SelectorList::parse_disallow_pseudo(
152 &selector_parser,
153 input,
154 parse_relative,
155 )?))
156 })
157 })
158}
159
160impl ScopeBounds {
161 pub fn parse<'a>(
163 context: &ParserContext,
164 input: &mut Parser<'a, '_>,
165 parse_relative: ParseRelative,
166 ) -> Result<Self, ParseError<'a>> {
167 let start = parse_scope(context, input, parse_relative, false)?;
168 let end = parse_scope(context, input, parse_relative, true)?;
169 Ok(Self { start, end })
170 }
171}
172
173#[derive(Debug, Copy, Clone, MallocSizeOf)]
175pub enum ImplicitScopeRoot {
176 InLightTree(OpaqueElement),
178 DocumentElement,
182 Constructed,
185 InShadowTree(OpaqueElement),
187 ShadowHost(OpaqueElement),
189}
190
191impl ImplicitScopeRoot {
192 pub fn matches_shadow_host(&self) -> bool {
194 match self {
195 Self::InLightTree(..) | Self::InShadowTree(..) | Self::DocumentElement => false,
196 Self::ShadowHost(..) | Self::Constructed => true,
197 }
198 }
199
200 pub fn element(&self, current_host: Option<OpaqueElement>) -> ImplicitScopeTarget {
202 match self {
203 Self::InLightTree(e) | Self::InShadowTree(e) | Self::ShadowHost(e) => {
204 ImplicitScopeTarget::Element(*e)
205 },
206 Self::Constructed | Self::DocumentElement => {
207 if matches!(self, Self::Constructed) {
208 if let Some(host) = current_host {
209 return ImplicitScopeTarget::Element(host);
210 }
211 }
212 ImplicitScopeTarget::DocumentElement
213 },
214 }
215 }
216}
217
218pub enum ImplicitScopeTarget {
220 Element(OpaqueElement),
222 DocumentElement,
224}
225
226impl ImplicitScopeTarget {
227 fn check<E: TElement>(&self, element: E) -> bool {
229 match self {
230 Self::Element(e) => element.opaque() == *e,
231 Self::DocumentElement => element.is_root(),
232 }
233 }
234}
235
236pub enum ScopeTarget<'a> {
238 Selector(&'a SelectorList<SelectorImpl>),
240 Implicit(ImplicitScopeTarget),
242}
243
244impl<'a> ScopeTarget<'a> {
245 fn check<E: TElement>(
247 &self,
248 element: E,
249 scope: Option<OpaqueElement>,
250 scope_subject_map: &ScopeSubjectMap,
251 context: &mut MatchingContext<E::Impl>,
252 ) -> bool {
253 match self {
254 Self::Selector(list) => context.nest_for_scope_condition(scope, |context| {
255 if scope_subject_map.early_reject(element, context.quirks_mode()) {
256 return false;
257 }
258 for selector in list.slice().iter() {
259 if matches_selector(selector, 0, None, &element, context) {
260 return true;
261 }
262 }
263 false
264 }),
265 Self::Implicit(t) => t.check(element),
266 }
267 }
268}
269
270#[derive(Clone, Copy, Debug)]
272pub struct ScopeRootCandidate {
273 pub root: OpaqueElement,
275 pub proximity: ScopeProximity,
277}
278
279pub fn collect_scope_roots<E>(
282 element: E,
283 ceiling: Option<OpaqueElement>,
284 context: &mut MatchingContext<E::Impl>,
285 target: &ScopeTarget,
286 matches_shadow_host: bool,
287 scope_subject_map: &ScopeSubjectMap,
288) -> Vec<ScopeRootCandidate>
289where
290 E: TElement,
291{
292 let mut result = vec![];
293 let mut parent = Some(element);
294 let mut proximity = 0usize;
295 while let Some(p) = parent {
296 if ceiling == Some(p.opaque()) {
297 break;
298 }
299 if target.check(p, ceiling, scope_subject_map, context) {
300 result.push(ScopeRootCandidate {
301 root: p.opaque(),
302 proximity: ScopeProximity::new(proximity),
303 });
304 }
307 parent = p.parent_element();
308 proximity += 1;
309 if parent.is_none() && matches_shadow_host {
312 parent = p.containing_shadow_host();
313 }
314 }
315 result
316}
317
318pub fn element_is_outside_of_scope<E>(
321 selector: &Selector<E::Impl>,
322 element: E,
323 root: OpaqueElement,
324 context: &mut MatchingContext<E::Impl>,
325 root_may_be_shadow_host: bool,
326) -> bool
327where
328 E: TElement,
329{
330 let mut parent = Some(element);
331 context.nest_for_scope_condition(Some(root), |context| {
332 while let Some(p) = parent {
333 if matches_selector(selector, 0, None, &p, context) {
334 return true;
335 }
336 if p.opaque() == root {
337 break;
339 }
340 parent = p.parent_element();
341 if parent.is_none() && root_may_be_shadow_host {
342 if let Some(host) = p.containing_shadow_host() {
343 return host.opaque() == root;
345 }
346 }
347 }
348 return false;
349 })
350}
351
352#[derive(Clone, Debug, Default, MallocSizeOf)]
355pub struct ScopeSubjectMap {
356 buckets: SimpleBucketsMap<()>,
357 any: bool,
358}
359
360impl ScopeSubjectMap {
361 pub fn add_bound_start(&mut self, selectors: &SelectorList<SelectorImpl>, quirks_mode: QuirksMode) {
363 if self.add_selector_list(selectors, quirks_mode) {
364 self.any = true;
365 }
366 }
367
368 fn add_selector_list(&mut self, selectors: &SelectorList<SelectorImpl>, quirks_mode: QuirksMode) -> bool {
369 let mut is_any = false;
370 for selector in selectors.slice().iter() {
371 is_any = is_any || self.add_selector(selector, quirks_mode);
372 }
373 is_any
374 }
375
376 fn add_selector(&mut self, selector: &Selector<SelectorImpl>, quirks_mode: QuirksMode) -> bool {
377 let mut is_any = true;
378 let mut iter = selector.iter();
379 while let Some(c) = iter.next() {
380 let component_any = match c {
381 Component::Class(cls) => {
382 match self.buckets.classes.try_entry(cls.0.clone(), quirks_mode) {
383 Ok(e) => {
384 e.or_insert(());
385 false
386 },
387 Err(_) => true,
388 }
389 },
390 Component::ID(id) => {
391 match self.buckets.ids.try_entry(id.0.clone(), quirks_mode) {
392 Ok(e) => {
393 e.or_insert(());
394 false
395 },
396 Err(_) => true,
397 }
398 },
399 Component::LocalName(local_name) => {
400 self.buckets.local_names.insert(local_name.lower_name.clone(), ());
401 false
402 },
403 Component::Is(ref list) | Component::Where(ref list) => {
404 self.add_selector_list(list, quirks_mode)
405 },
406 _ => true,
407 };
408
409 is_any = is_any && component_any;
410 }
411 is_any
412 }
413
414 pub fn shrink_if_needed(&mut self) {
416 self.buckets.shrink_if_needed();
417 }
418
419 pub fn clear(&mut self) {
421 self.buckets.clear();
422 self.any = false;
423 }
424
425 fn early_reject<E: TElement>(&self, element: E, quirks_mode: QuirksMode) -> bool {
427 if self.any {
428 return false;
429 }
430
431 if let Some(id) = element.id() {
432 if self.buckets.ids.get(id, quirks_mode).is_some() {
433 return false;
434 }
435 }
436
437 let mut found = false;
438 element.each_class(|cls| {
439 if self.buckets.classes.get(cls, quirks_mode).is_some() {
440 found = true;
441 }
442 });
443 if found {
444 return false;
445 }
446
447 if self.buckets.local_names.get(element.local_name()).is_some() {
448 return false;
449 }
450
451 true
452 }
453}
454
455pub fn scope_selector_list_is_trivial(list: &SelectorList<SelectorImpl>) -> bool {
457 fn scope_selector_is_trivial(selector: &Selector<SelectorImpl>) -> bool {
458 let mut iter = selector.iter();
465 loop {
466 while let Some(c) = iter.next() {
467 match c {
468 Component::ID(_) | Component::Nth(_) | Component::NthOf(_) | Component::Has(_) => return false,
469 Component::Is(ref list) | Component::Where(ref list) | Component::Negation(ref list) =>
470 if !scope_selector_list_is_trivial(list) {
471 return false;
472 }
473 _ => (),
474 }
475 }
476
477 match iter.next_sequence() {
478 Some(c) => if c.is_sibling() {
479 return false;
480 },
481 None => return true,
482 }
483 }
484 }
485
486 list.slice().iter().all(|s| scope_selector_is_trivial(s))
487}