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