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 let selector_parser = SelectorParser {
131 stylesheet_origin: context.stylesheet_origin,
132 namespaces: &context.namespaces,
133 url_data: context.url_data,
134 for_supports_rule: false,
135 };
136 let parse_relative = if for_end {
137 ParseRelative::ForScope
138 } else {
139 parse_relative
140 };
141 Ok(Some(SelectorList::parse_disallow_pseudo(
142 &selector_parser,
143 input,
144 parse_relative,
145 )?))
146 })
147 })
148}
149
150impl ScopeBounds {
151 pub fn parse<'a>(
153 context: &ParserContext,
154 input: &mut Parser<'a, '_>,
155 parse_relative: ParseRelative,
156 ) -> Result<Self, ParseError<'a>> {
157 let start = parse_scope(context, input, parse_relative, false)?;
158 let end = parse_scope(context, input, parse_relative, true)?;
159 Ok(Self { start, end })
160 }
161}
162
163#[derive(Debug, Copy, Clone, MallocSizeOf)]
165pub enum ImplicitScopeRoot {
166 InLightTree(OpaqueElement),
168 DocumentElement,
172 Constructed,
175 InShadowTree(OpaqueElement),
177 ShadowHost(OpaqueElement),
179}
180
181impl ImplicitScopeRoot {
182 pub fn matches_shadow_host(&self) -> bool {
184 match self {
185 Self::InLightTree(..) | Self::InShadowTree(..) | Self::DocumentElement => false,
186 Self::ShadowHost(..) | Self::Constructed => true,
187 }
188 }
189
190 pub fn element(&self, current_host: Option<OpaqueElement>) -> ImplicitScopeTarget {
192 match self {
193 Self::InLightTree(e) | Self::InShadowTree(e) | Self::ShadowHost(e) => {
194 ImplicitScopeTarget::Element(*e)
195 },
196 Self::Constructed | Self::DocumentElement => {
197 if matches!(self, Self::Constructed) {
198 if let Some(host) = current_host {
199 return ImplicitScopeTarget::Element(host);
200 }
201 }
202 ImplicitScopeTarget::DocumentElement
203 },
204 }
205 }
206}
207
208pub enum ImplicitScopeTarget {
210 Element(OpaqueElement),
212 DocumentElement,
214}
215
216impl ImplicitScopeTarget {
217 fn check<E: TElement>(&self, element: E) -> bool {
219 match self {
220 Self::Element(e) => element.opaque() == *e,
221 Self::DocumentElement => element.is_root(),
222 }
223 }
224}
225
226pub enum ScopeTarget<'a> {
228 Selector(&'a SelectorList<SelectorImpl>),
230 Implicit(ImplicitScopeTarget),
232}
233
234impl<'a> ScopeTarget<'a> {
235 fn check<E: TElement>(
237 &self,
238 element: E,
239 scope: Option<OpaqueElement>,
240 scope_subject_map: &ScopeSubjectMap,
241 context: &mut MatchingContext<E::Impl>,
242 ) -> bool {
243 match self {
244 Self::Selector(list) => context.nest_for_scope_condition(scope, |context| {
245 if scope_subject_map.early_reject(element, context.quirks_mode()) {
246 return false;
247 }
248 for selector in list.slice().iter() {
249 if matches_selector(selector, 0, None, &element, context) {
250 return true;
251 }
252 }
253 false
254 }),
255 Self::Implicit(t) => t.check(element),
256 }
257 }
258}
259
260#[derive(Clone, Copy, Debug)]
262pub struct ScopeRootCandidate {
263 pub root: OpaqueElement,
265 pub proximity: ScopeProximity,
267}
268
269impl ScopeRootCandidate {
270 pub fn get_scope_root_element<E>(&self, originating_element: E) -> Option<E>
272 where
273 E: TElement,
274 {
275 let mut e = originating_element;
279 let hops = self.proximity.get()?;
280 for _ in 0..hops {
281 e = e.parent_element()?;
282 }
283 debug_assert_eq!(e.opaque(), self.root);
284 Some(e)
285 }
286}
287
288pub fn collect_scope_roots<E>(
291 element: E,
292 ceiling: Option<OpaqueElement>,
293 context: &mut MatchingContext<E::Impl>,
294 target: &ScopeTarget,
295 matches_shadow_host: bool,
296 scope_subject_map: &ScopeSubjectMap,
297) -> Vec<ScopeRootCandidate>
298where
299 E: TElement,
300{
301 let mut result = vec![];
302 let mut parent = Some(element);
303 let mut proximity = 0usize;
304 while let Some(p) = parent {
305 if target.check(p, ceiling, scope_subject_map, context) {
306 result.push(ScopeRootCandidate {
307 root: p.opaque(),
308 proximity: ScopeProximity::new(proximity),
309 });
310 }
313 if ceiling == Some(p.opaque()) {
314 break;
315 }
316 parent = p.parent_element();
317 proximity += 1;
318 if parent.is_none() && matches_shadow_host {
321 parent = p.containing_shadow_host();
322 }
323 }
324 result
325}
326
327pub fn element_is_outside_of_scope<E>(
330 selector: &Selector<E::Impl>,
331 element: E,
332 root: OpaqueElement,
333 context: &mut MatchingContext<E::Impl>,
334 root_may_be_shadow_host: bool,
335) -> bool
336where
337 E: TElement,
338{
339 let mut parent = Some(element);
340 context.nest_for_scope_condition(Some(root), |context| {
341 while let Some(p) = parent {
342 if matches_selector(selector, 0, None, &p, context) {
343 return true;
344 }
345 if p.opaque() == root {
346 break;
348 }
349 parent = p.parent_element();
350 if parent.is_none() && root_may_be_shadow_host {
351 if let Some(host) = p.containing_shadow_host() {
352 return host.opaque() == root;
354 }
355 }
356 }
357 return false;
358 })
359}
360
361#[derive(Clone, Debug, Default, MallocSizeOf)]
364pub struct ScopeSubjectMap {
365 buckets: SimpleBucketsMap<()>,
366 any: bool,
367}
368
369impl ScopeSubjectMap {
370 pub fn add_bound_start(
372 &mut self,
373 selectors: &SelectorList<SelectorImpl>,
374 quirks_mode: QuirksMode,
375 ) {
376 if self.add_selector_list(selectors, quirks_mode) {
377 self.any = true;
378 }
379 }
380
381 fn add_selector_list(
382 &mut self,
383 selectors: &SelectorList<SelectorImpl>,
384 quirks_mode: QuirksMode,
385 ) -> bool {
386 let mut is_any = false;
387 for selector in selectors.slice().iter() {
388 is_any = is_any || self.add_selector(selector, quirks_mode);
389 }
390 is_any
391 }
392
393 fn add_selector(&mut self, selector: &Selector<SelectorImpl>, quirks_mode: QuirksMode) -> bool {
394 let mut is_any = true;
395 let mut iter = selector.iter();
396 while let Some(c) = iter.next() {
397 let component_any = match c {
398 Component::Class(cls) => {
399 match self.buckets.classes.try_entry(cls.0.clone(), quirks_mode) {
400 Ok(e) => {
401 e.or_insert(());
402 false
403 },
404 Err(_) => true,
405 }
406 },
407 Component::ID(id) => match self.buckets.ids.try_entry(id.0.clone(), quirks_mode) {
408 Ok(e) => {
409 e.or_insert(());
410 false
411 },
412 Err(_) => true,
413 },
414 Component::LocalName(local_name) => {
415 self.buckets
416 .local_names
417 .insert(local_name.lower_name.clone(), ());
418 false
419 },
420 Component::Is(ref list) | Component::Where(ref list) => {
421 self.add_selector_list(list, quirks_mode)
422 },
423 _ => true,
424 };
425
426 is_any = is_any && component_any;
427 }
428 is_any
429 }
430
431 pub fn shrink_if_needed(&mut self) {
433 self.buckets.shrink_if_needed();
434 }
435
436 pub fn clear(&mut self) {
438 self.buckets.clear();
439 self.any = false;
440 }
441
442 fn early_reject<E: TElement>(&self, element: E, quirks_mode: QuirksMode) -> bool {
444 if self.any {
445 return false;
446 }
447
448 if let Some(id) = element.id() {
449 if self.buckets.ids.get(id, quirks_mode).is_some() {
450 return false;
451 }
452 }
453
454 let mut found = false;
455 element.each_class(|cls| {
456 if self.buckets.classes.get(cls, quirks_mode).is_some() {
457 found = true;
458 }
459 });
460 if found {
461 return false;
462 }
463
464 if self.buckets.local_names.get(element.local_name()).is_some() {
465 return false;
466 }
467
468 true
469 }
470}
471
472pub fn scope_selector_list_is_trivial(list: &SelectorList<SelectorImpl>) -> bool {
474 fn scope_selector_is_trivial(selector: &Selector<SelectorImpl>) -> bool {
475 let mut iter = selector.iter();
482 loop {
483 while let Some(c) = iter.next() {
484 match c {
485 Component::ID(_)
486 | Component::Nth(_)
487 | Component::NthOf(_)
488 | Component::Has(_) => return false,
489 Component::Is(ref list)
490 | Component::Where(ref list)
491 | Component::Negation(ref list) => {
492 if !scope_selector_list_is_trivial(list) {
493 return false;
494 }
495 },
496 _ => (),
497 }
498 }
499
500 match iter.next_sequence() {
501 Some(c) => {
502 if c.is_sibling() {
503 return false;
504 }
505 },
506 None => return true,
507 }
508 }
509 }
510
511 list.slice().iter().all(|s| scope_selector_is_trivial(s))
512}