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