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::simple_buckets_map::SimpleBucketsMap;
17use crate::stylesheets::CssRules;
18use cssparser::{Parser, SourceLocation, ToCss};
19#[cfg(feature = "gecko")]
20use malloc_size_of::{
21 MallocSizeOfOps, MallocUnconditionalShallowSizeOf, MallocUnconditionalSizeOf,
22};
23use selectors::context::{MatchingContext, QuirksMode};
24use selectors::matching::matches_selector;
25use selectors::parser::{Component, ParseRelative, Selector, SelectorList};
26use selectors::OpaqueElement;
27use servo_arc::Arc;
28use std::fmt::{self, Write};
29use style_traits::{CssStringWriter, CssWriter, ParseError};
30
31#[derive(Debug, ToShmem)]
33pub struct ScopeRule {
34 pub bounds: ScopeBounds,
36 pub rules: Arc<Locked<CssRules>>,
38 pub source_location: SourceLocation,
40}
41
42impl DeepCloneWithLock for ScopeRule {
43 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
44 let rules = self.rules.read_with(guard);
45 Self {
46 bounds: self.bounds.clone(),
47 rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard))),
48 source_location: self.source_location.clone(),
49 }
50 }
51}
52
53impl ToCssWithGuard for ScopeRule {
54 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
55 dest.write_str("@scope")?;
56 {
57 let mut writer = CssWriter::new(dest);
58 if let Some(start) = self.bounds.start.as_ref() {
59 writer.write_str(" (")?;
60 start.to_css(&mut writer)?;
61 writer.write_char(')')?;
62 }
63 if let Some(end) = self.bounds.end.as_ref() {
64 writer.write_str(" to (")?;
65 end.to_css(&mut writer)?;
66 writer.write_char(')')?;
67 }
68 }
69 self.rules.read_with(guard).to_css_block(guard, dest)
70 }
71}
72
73impl ScopeRule {
74 #[cfg(feature = "gecko")]
76 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
77 self.rules.unconditional_shallow_size_of(ops)
78 + self.rules.read_with(guard).size_of(guard, ops)
79 + self.bounds.size_of(ops)
80 }
81}
82
83#[derive(Debug, Clone, ToShmem)]
85pub struct ScopeBounds {
86 pub start: Option<SelectorList<SelectorImpl>>,
88 pub end: Option<SelectorList<SelectorImpl>>,
90}
91
92impl ScopeBounds {
93 #[cfg(feature = "gecko")]
94 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
95 fn bound_size_of(
96 bound: &Option<SelectorList<SelectorImpl>>,
97 ops: &mut MallocSizeOfOps,
98 ) -> usize {
99 bound
100 .as_ref()
101 .map(|list| list.unconditional_size_of(ops))
102 .unwrap_or(0)
103 }
104 bound_size_of(&self.start, ops) + bound_size_of(&self.end, ops)
105 }
106}
107
108fn parse_scope<'a>(
109 context: &ParserContext,
110 input: &mut Parser<'a, '_>,
111 parse_relative: ParseRelative,
112 for_end: bool,
113) -> Result<Option<SelectorList<SelectorImpl>>, ParseError<'a>> {
114 input.try_parse(|input| {
115 if for_end {
116 if input.try_parse(|i| i.expect_ident_matching("to")).is_err() {
118 return Ok(None);
119 }
120 }
121 let parens = input.try_parse(|i| i.expect_parenthesis_block());
122 if for_end {
123 parens?;
125 } else if parens.is_err() {
126 return Ok(None);
128 }
129 input.parse_nested_block(|input| {
130 if input.is_exhausted() {
131 return Ok(None);
133 }
134 let selector_parser = SelectorParser {
135 stylesheet_origin: context.stylesheet_origin,
136 namespaces: &context.namespaces,
137 url_data: context.url_data,
138 for_supports_rule: false,
139 };
140 let parse_relative = if for_end {
141 ParseRelative::ForScope
142 } else {
143 parse_relative
144 };
145 Ok(Some(SelectorList::parse_disallow_pseudo(
146 &selector_parser,
147 input,
148 parse_relative,
149 )?))
150 })
151 })
152}
153
154impl ScopeBounds {
155 pub fn parse<'a>(
157 context: &ParserContext,
158 input: &mut Parser<'a, '_>,
159 parse_relative: ParseRelative,
160 ) -> Result<Self, ParseError<'a>> {
161 let start = parse_scope(context, input, parse_relative, false)?;
162 let end = parse_scope(context, input, parse_relative, true)?;
163 Ok(Self { start, end })
164 }
165}
166
167#[derive(Debug, Copy, Clone, MallocSizeOf)]
169pub enum ImplicitScopeRoot {
170 InLightTree(OpaqueElement),
172 DocumentElement,
176 Constructed,
179 InShadowTree(OpaqueElement),
181 ShadowHost(OpaqueElement),
183}
184
185impl ImplicitScopeRoot {
186 pub fn matches_shadow_host(&self) -> bool {
188 match self {
189 Self::InLightTree(..) | Self::InShadowTree(..) | Self::DocumentElement => false,
190 Self::ShadowHost(..) | Self::Constructed => true,
191 }
192 }
193
194 pub fn element(&self, current_host: Option<OpaqueElement>) -> ImplicitScopeTarget {
196 match self {
197 Self::InLightTree(e) | Self::InShadowTree(e) | Self::ShadowHost(e) => {
198 ImplicitScopeTarget::Element(*e)
199 },
200 Self::Constructed | Self::DocumentElement => {
201 if matches!(self, Self::Constructed) {
202 if let Some(host) = current_host {
203 return ImplicitScopeTarget::Element(host);
204 }
205 }
206 ImplicitScopeTarget::DocumentElement
207 },
208 }
209 }
210}
211
212pub enum ImplicitScopeTarget {
214 Element(OpaqueElement),
216 DocumentElement,
218}
219
220impl ImplicitScopeTarget {
221 fn check<E: TElement>(&self, element: E) -> bool {
223 match self {
224 Self::Element(e) => element.opaque() == *e,
225 Self::DocumentElement => element.is_root(),
226 }
227 }
228}
229
230pub enum ScopeTarget<'a> {
232 Selector(&'a SelectorList<SelectorImpl>),
234 Implicit(ImplicitScopeTarget),
236}
237
238impl<'a> ScopeTarget<'a> {
239 fn check<E: TElement>(
241 &self,
242 element: E,
243 scope: Option<OpaqueElement>,
244 scope_subject_map: &ScopeSubjectMap,
245 context: &mut MatchingContext<E::Impl>,
246 ) -> bool {
247 match self {
248 Self::Selector(list) => context.nest_for_scope_condition(scope, |context| {
249 if scope_subject_map.early_reject(element, context.quirks_mode()) {
250 return false;
251 }
252 for selector in list.slice().iter() {
253 if matches_selector(selector, 0, None, &element, context) {
254 return true;
255 }
256 }
257 false
258 }),
259 Self::Implicit(t) => t.check(element),
260 }
261 }
262}
263
264#[derive(Clone, Copy, Debug)]
266pub struct ScopeRootCandidate {
267 pub root: OpaqueElement,
269 pub proximity: ScopeProximity,
271}
272
273impl ScopeRootCandidate {
274 pub fn get_scope_root_element<E>(&self, originating_element: E) -> Option<E>
276 where
277 E: TElement,
278 {
279 let mut e = originating_element;
283 let hops = self.proximity.get()?;
284 for _ in 0..hops {
285 e = e.parent_element()?;
286 }
287 debug_assert_eq!(e.opaque(), self.root);
288 Some(e)
289 }
290}
291
292pub fn collect_scope_roots<E>(
295 element: E,
296 ceiling: Option<OpaqueElement>,
297 context: &mut MatchingContext<E::Impl>,
298 target: &ScopeTarget,
299 matches_shadow_host: bool,
300 scope_subject_map: &ScopeSubjectMap,
301) -> Vec<ScopeRootCandidate>
302where
303 E: TElement,
304{
305 let mut result = vec![];
306 let mut parent = Some(element);
307 let mut proximity = 0usize;
308 while let Some(p) = parent {
309 if ceiling == Some(p.opaque()) {
310 break;
311 }
312 if target.check(p, ceiling, scope_subject_map, context) {
313 result.push(ScopeRootCandidate {
314 root: p.opaque(),
315 proximity: ScopeProximity::new(proximity),
316 });
317 }
320 parent = p.parent_element();
321 proximity += 1;
322 if parent.is_none() && matches_shadow_host {
325 parent = p.containing_shadow_host();
326 }
327 }
328 result
329}
330
331pub fn element_is_outside_of_scope<E>(
334 selector: &Selector<E::Impl>,
335 element: E,
336 root: OpaqueElement,
337 context: &mut MatchingContext<E::Impl>,
338 root_may_be_shadow_host: bool,
339) -> bool
340where
341 E: TElement,
342{
343 let mut parent = Some(element);
344 context.nest_for_scope_condition(Some(root), |context| {
345 while let Some(p) = parent {
346 if matches_selector(selector, 0, None, &p, context) {
347 return true;
348 }
349 if p.opaque() == root {
350 break;
352 }
353 parent = p.parent_element();
354 if parent.is_none() && root_may_be_shadow_host {
355 if let Some(host) = p.containing_shadow_host() {
356 return host.opaque() == root;
358 }
359 }
360 }
361 return false;
362 })
363}
364
365#[derive(Clone, Debug, Default, MallocSizeOf)]
368pub struct ScopeSubjectMap {
369 buckets: SimpleBucketsMap<()>,
370 any: bool,
371}
372
373impl ScopeSubjectMap {
374 pub fn add_bound_start(
376 &mut self,
377 selectors: &SelectorList<SelectorImpl>,
378 quirks_mode: QuirksMode,
379 ) {
380 if self.add_selector_list(selectors, quirks_mode) {
381 self.any = true;
382 }
383 }
384
385 fn add_selector_list(
386 &mut self,
387 selectors: &SelectorList<SelectorImpl>,
388 quirks_mode: QuirksMode,
389 ) -> bool {
390 let mut is_any = false;
391 for selector in selectors.slice().iter() {
392 is_any = is_any || self.add_selector(selector, quirks_mode);
393 }
394 is_any
395 }
396
397 fn add_selector(&mut self, selector: &Selector<SelectorImpl>, quirks_mode: QuirksMode) -> bool {
398 let mut is_any = true;
399 let mut iter = selector.iter();
400 while let Some(c) = iter.next() {
401 let component_any = match c {
402 Component::Class(cls) => {
403 match self.buckets.classes.try_entry(cls.0.clone(), quirks_mode) {
404 Ok(e) => {
405 e.or_insert(());
406 false
407 },
408 Err(_) => true,
409 }
410 },
411 Component::ID(id) => match self.buckets.ids.try_entry(id.0.clone(), quirks_mode) {
412 Ok(e) => {
413 e.or_insert(());
414 false
415 },
416 Err(_) => true,
417 },
418 Component::LocalName(local_name) => {
419 self.buckets
420 .local_names
421 .insert(local_name.lower_name.clone(), ());
422 false
423 },
424 Component::Is(ref list) | Component::Where(ref list) => {
425 self.add_selector_list(list, quirks_mode)
426 },
427 _ => true,
428 };
429
430 is_any = is_any && component_any;
431 }
432 is_any
433 }
434
435 pub fn shrink_if_needed(&mut self) {
437 self.buckets.shrink_if_needed();
438 }
439
440 pub fn clear(&mut self) {
442 self.buckets.clear();
443 self.any = false;
444 }
445
446 fn early_reject<E: TElement>(&self, element: E, quirks_mode: QuirksMode) -> bool {
448 if self.any {
449 return false;
450 }
451
452 if let Some(id) = element.id() {
453 if self.buckets.ids.get(id, quirks_mode).is_some() {
454 return false;
455 }
456 }
457
458 let mut found = false;
459 element.each_class(|cls| {
460 if self.buckets.classes.get(cls, quirks_mode).is_some() {
461 found = true;
462 }
463 });
464 if found {
465 return false;
466 }
467
468 if self.buckets.local_names.get(element.local_name()).is_some() {
469 return false;
470 }
471
472 true
473 }
474}
475
476pub fn scope_selector_list_is_trivial(list: &SelectorList<SelectorImpl>) -> bool {
478 fn scope_selector_is_trivial(selector: &Selector<SelectorImpl>) -> bool {
479 let mut iter = selector.iter();
486 loop {
487 while let Some(c) = iter.next() {
488 match c {
489 Component::ID(_)
490 | Component::Nth(_)
491 | Component::NthOf(_)
492 | Component::Has(_) => return false,
493 Component::Is(ref list)
494 | Component::Where(ref list)
495 | Component::Negation(ref list) => {
496 if !scope_selector_list_is_trivial(list) {
497 return false;
498 }
499 },
500 _ => (),
501 }
502 }
503
504 match iter.next_sequence() {
505 Some(c) => {
506 if c.is_sibling() {
507 return false;
508 }
509 },
510 None => return true,
511 }
512 }
513 }
514
515 list.slice().iter().all(|s| scope_selector_is_trivial(s))
516}