lewp_css/domain/selectors/
non_tree_structural_pseudo_class.rs

1// This file is part of css. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT. No part of predicator, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
2// Copyright © 2017 The developers of css. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT.
3
4use {
5    super::{
6        DeduplicatedSelectors,
7        LanguageRange,
8        OurSelectorExt,
9        VendorPrefixablePseudoClassName,
10    },
11    crate::{
12        domain::{
13            selectors::{
14                LanguageRanges,
15                OurSelectorImpl,
16                SystemMetric,
17                TextDirectionality,
18                TreeHover,
19            },
20            Atom,
21            VendorPrefix::{self, *},
22        },
23        parsers::OurSelectorParser,
24        CustomParseError,
25    },
26    cssparser::{CowRcStr, ParseError, Parser, ToCss},
27    selectors::parser::NonTSPseudoClass,
28    std::{collections::HashMap, fmt},
29};
30
31//noinspection SpellCheckingInspection
32/// A non tree-structural pseudo-class.
33/// See <https://drafts.csswg.org/selectors-4/#structural-pseudos>
34#[derive(Clone, Debug, Eq, PartialEq)]
35#[allow(missing_docs)]
36pub enum NonTreeStructuralPseudoClass {
37    active,
38    any(Option<VendorPrefix>, DeduplicatedSelectors),
39    any_link(Option<VendorPrefix>),
40    checked,
41    default,
42    dir(Option<VendorPrefix>, TextDirectionality),
43    disabled,
44    enabled,
45    /// Only valid in @page
46    first,
47    focus,
48    focus_within,
49    in_range,
50    invalid,
51    is(DeduplicatedSelectors),
52    fullscreen(Option<VendorPrefix>),
53    hover,
54    indeterminate,
55    lang(LanguageRanges),
56    /// Only valid in @page
57    left,
58    link,
59    optional,
60    out_of_range,
61    /// The obsolete (as of Firefox 51) `:-moz-placeholder` is re-written when parsed as this.
62    placeholder_shown(Option<VendorPrefix>),
63    read_only(Option<VendorPrefix>),
64    read_write(Option<VendorPrefix>),
65    required,
66    /// Only valid in @page
67    right,
68    target,
69    valid,
70    visited,
71    where_(DeduplicatedSelectors),
72
73    /// -servo- only
74    case_sensitive_type_attr(Option<VendorPrefix>, Atom),
75
76    /// -servo- only
77    non_zero_border(Option<VendorPrefix>),
78
79    /// -moz- only
80    broken(Option<VendorPrefix>),
81
82    /// -moz- only
83    drag_over(Option<VendorPrefix>),
84
85    /// -moz- only
86    first_node(Option<VendorPrefix>),
87
88    /// -moz- only
89    focusring(Option<VendorPrefix>),
90
91    /// -moz- only
92    full_screen_ancestor(Option<VendorPrefix>),
93
94    /// -moz- only
95    handler_blocked(Option<VendorPrefix>),
96
97    /// -moz- only
98    handler_crashed(Option<VendorPrefix>),
99
100    /// -moz- only
101    handler_disabled(Option<VendorPrefix>),
102
103    /// -moz- only
104    last_node(Option<VendorPrefix>),
105
106    /// -moz- only
107    list_bullet(Option<VendorPrefix>),
108
109    /// -moz- only
110    list_number(Option<VendorPrefix>),
111
112    /// -moz- only
113    loading(Option<VendorPrefix>),
114
115    //  -moz- only
116    locale_dir(Option<VendorPrefix>, TextDirectionality),
117
118    /// -moz- only
119    lwtheme(Option<VendorPrefix>),
120
121    /// -moz- only
122    lwtheme_brighttext(Option<VendorPrefix>),
123
124    /// -moz- only
125    lwtheme_darktext(Option<VendorPrefix>),
126
127    /// -moz- only
128    native_anonymous(Option<VendorPrefix>),
129
130    /// -moz- only
131    only_whitespace(Option<VendorPrefix>),
132
133    /// -moz- only
134    submit_invalid(Option<VendorPrefix>),
135
136    /// -moz- only
137    suppressed(Option<VendorPrefix>),
138
139    /// -moz- only (not listed with other pseudo-classes)
140    system_metric(Option<VendorPrefix>, SystemMetric),
141
142    /// -moz- only
143    tree_cell(Option<VendorPrefix>),
144
145    /// -moz- only.
146    // A psuedo-class function with one value, hover
147    tree_cell_text(Option<VendorPrefix>, TreeHover),
148
149    /// -moz- only
150    tree_checkbox(Option<VendorPrefix>),
151
152    /// -moz- only
153    tree_column(Option<VendorPrefix>),
154
155    /// -moz- only
156    tree_drop_feedback(Option<VendorPrefix>),
157
158    /// -moz- only
159    tree_image(Option<VendorPrefix>),
160
161    /// -moz- only
162    tree_indentation(Option<VendorPrefix>),
163
164    /// -moz- only
165    tree_line(Option<VendorPrefix>),
166
167    /// -moz- only
168    tree_progressmeter(Option<VendorPrefix>),
169
170    /// -moz- only.
171    // A psuedo-class function with one value, hover
172    tree_row(Option<VendorPrefix>, TreeHover),
173
174    /// -moz- only
175    tree_separator(Option<VendorPrefix>),
176
177    /// -moz- only
178    tree_twisty(Option<VendorPrefix>),
179
180    /// -moz- only
181    ui_invalid(Option<VendorPrefix>),
182
183    /// -moz- only
184    ui_valid(Option<VendorPrefix>),
185
186    /// -moz- only
187    user_disabled(Option<VendorPrefix>),
188
189    /// -moz- only
190    window_inactive(Option<VendorPrefix>),
191
192    /// -webkit- only, with potential Mozilla support coming.
193    autofill(Option<VendorPrefix>),
194}
195
196impl NonTSPseudoClass for NonTreeStructuralPseudoClass {
197    type Impl = OurSelectorImpl;
198
199    fn is_active_or_hover(&self) -> bool {
200        matches!(self, Self::active | Self::hover)
201    }
202
203    fn is_user_action_state(&self) -> bool {
204        matches!(
205            self,
206            Self::active
207                | Self::hover
208                | Self::visited
209                | Self::link
210                | Self::focus
211        )
212    }
213}
214
215impl ToCss for NonTreeStructuralPseudoClass {
216    //noinspection SpellCheckingInspection
217    fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
218        #[inline(always)]
219        fn write<W: fmt::Write>(
220            dest: &mut W,
221            classWithColon: &str,
222        ) -> fmt::Result {
223            dest.write_str(classWithColon)
224        }
225
226        #[inline(always)]
227        fn write_with_vendor_prefix<W: fmt::Write>(
228            dest: &mut W,
229            vendorPrefix: &Option<VendorPrefix>,
230            classWithoutColon: &str,
231        ) -> fmt::Result {
232            dest.write_char(':')?;
233            if let &Some(ref vendorPrefix) = vendorPrefix {
234                vendorPrefix.to_css(dest)?;
235            }
236            dest.write_str(classWithoutColon)
237        }
238
239        #[inline(always)]
240        fn write_with_vendor_prefix_value<W: fmt::Write, T: ToCss>(
241            dest: &mut W,
242            vendorPrefix: &Option<VendorPrefix>,
243            classWithoutColon: &str,
244            value: &T,
245        ) -> fmt::Result {
246            dest.write_char(':')?;
247            if let &Some(ref vendorPrefix) = vendorPrefix {
248                vendorPrefix.to_css(dest)?;
249            }
250            dest.write_str(classWithoutColon)?;
251            dest.write_char('(')?;
252            value.to_css(dest)?;
253            dest.write_char(')')
254        }
255
256        #[inline(always)]
257        fn write_with_value<W: fmt::Write, T: ToCss>(
258            dest: &mut W,
259            classWithoutColon: &str,
260            value: &T,
261        ) -> fmt::Result {
262            dest.write_char(':')?;
263            dest.write_str(classWithoutColon)?;
264            dest.write_char('(')?;
265            value.to_css(dest)?;
266            dest.write_char(')')
267        }
268
269        match &*self {
270            Self::active => write(dest, ":active"),
271
272            Self::any(ref vendorPrefix, ref value) => {
273                write_with_vendor_prefix_value(dest, vendorPrefix, "any", value)
274            }
275
276            Self::any_link(ref vendorPrefix) => {
277                write_with_vendor_prefix(dest, vendorPrefix, "any-link")
278            }
279
280            Self::checked => write(dest, ":checked"),
281
282            Self::default => write(dest, ":default"),
283
284            Self::disabled => write(dest, ":disabled"),
285
286            Self::dir(ref vendorPrefix, ref value) => {
287                write_with_vendor_prefix_value(dest, vendorPrefix, "dir", value)
288            }
289
290            Self::enabled => write(dest, ":enabled"),
291
292            Self::first => write(dest, ":first"),
293
294            Self::focus => write(dest, ":focus"),
295
296            Self::focus_within => write(dest, ":focus-within"),
297
298            Self::fullscreen(ref vendorPrefix) => {
299                dest.write_char(':')?;
300                let name = if let &Some(ref vendorPrefix) = vendorPrefix {
301                    vendorPrefix.to_css(dest)?;
302
303                    match *vendorPrefix {
304                        moz => "full-screen",
305                        webkit => "full-screen",
306                        _ => "fullscreen",
307                    }
308                } else {
309                    "fullscreen"
310                };
311                dest.write_str(name)
312            }
313
314            Self::hover => write(dest, ":hover"),
315
316            Self::indeterminate => write(dest, ":indeterminate"),
317
318            Self::in_range => write(dest, ":in-range"),
319
320            Self::invalid => write(dest, ":invalid"),
321
322            Self::is(ref value) => write_with_value(dest, "is", value),
323
324            Self::lang(ref languages) => {
325                dest.write_str(":lang(")?;
326                languages.to_css(dest)?;
327                dest.write_char(')')
328            }
329
330            Self::left => write(dest, ":left"),
331
332            Self::link => write(dest, ":link"),
333
334            Self::optional => write(dest, ":optional"),
335
336            Self::out_of_range => write(dest, ":out-of-range"),
337
338            Self::placeholder_shown(ref vendorPrefix) => {
339                write_with_vendor_prefix(
340                    dest,
341                    vendorPrefix,
342                    "placeholder-shown",
343                )
344            }
345
346            Self::read_only(ref vendorPrefix) => {
347                write_with_vendor_prefix(dest, vendorPrefix, "read-only")
348            }
349
350            Self::read_write(ref vendorPrefix) => {
351                write_with_vendor_prefix(dest, vendorPrefix, "read-write")
352            }
353
354            Self::required => write(dest, ":required"),
355
356            Self::right => write(dest, ":right"),
357
358            Self::target => write(dest, ":target"),
359
360            Self::valid => write(dest, ":valid"),
361
362            Self::visited => write(dest, ":visited"),
363
364            Self::where_(ref value) => write_with_value(dest, "where", value),
365
366            // -servo- only
367            Self::case_sensitive_type_attr(ref vendorPrefix, ref value) => {
368                write_with_vendor_prefix_value(
369                    dest,
370                    vendorPrefix,
371                    "case-sensitive-type-attr",
372                    value,
373                )
374            }
375
376            Self::non_zero_border(ref vendorPrefix) => {
377                write_with_vendor_prefix(dest, vendorPrefix, "non-zero-border")
378            }
379
380            // -moz- only
381            Self::broken(ref vendorPrefix) => {
382                write_with_vendor_prefix(dest, vendorPrefix, "broken")
383            }
384
385            Self::drag_over(ref vendorPrefix) => {
386                write_with_vendor_prefix(dest, vendorPrefix, "drag-over")
387            }
388
389            Self::first_node(ref vendorPrefix) => {
390                write_with_vendor_prefix(dest, vendorPrefix, "first-node")
391            }
392
393            Self::focusring(ref vendorPrefix) => {
394                write_with_vendor_prefix(dest, vendorPrefix, "focusring")
395            }
396
397            Self::full_screen_ancestor(ref vendorPrefix) => {
398                write_with_vendor_prefix(
399                    dest,
400                    vendorPrefix,
401                    "full-screen-ancestor",
402                )
403            }
404
405            Self::handler_blocked(ref vendorPrefix) => {
406                write_with_vendor_prefix(dest, vendorPrefix, "handler-blocked")
407            }
408
409            Self::handler_crashed(ref vendorPrefix) => {
410                write_with_vendor_prefix(dest, vendorPrefix, "handler-crashed")
411            }
412
413            Self::handler_disabled(ref vendorPrefix) => {
414                write_with_vendor_prefix(dest, vendorPrefix, "handler-disabled")
415            }
416
417            Self::last_node(ref vendorPrefix) => {
418                write_with_vendor_prefix(dest, vendorPrefix, "last-node")
419            }
420
421            Self::list_bullet(ref vendorPrefix) => {
422                write_with_vendor_prefix(dest, vendorPrefix, "list-bullet")
423            }
424
425            Self::list_number(ref vendorPrefix) => {
426                write_with_vendor_prefix(dest, vendorPrefix, "list-number")
427            }
428
429            Self::loading(ref vendorPrefix) => {
430                write_with_vendor_prefix(dest, vendorPrefix, "loading")
431            }
432
433            Self::locale_dir(ref vendorPrefix, ref value) => {
434                write_with_vendor_prefix_value(
435                    dest,
436                    vendorPrefix,
437                    "locale-dir",
438                    value,
439                )
440            }
441
442            Self::lwtheme(ref vendorPrefix) => {
443                write_with_vendor_prefix(dest, vendorPrefix, "lwtheme")
444            }
445
446            Self::lwtheme_brighttext(ref vendorPrefix) => {
447                write_with_vendor_prefix(
448                    dest,
449                    vendorPrefix,
450                    "lwtheme-brighttext",
451                )
452            }
453
454            Self::lwtheme_darktext(ref vendorPrefix) => {
455                write_with_vendor_prefix(dest, vendorPrefix, "lwtheme-darktext")
456            }
457
458            Self::native_anonymous(ref vendorPrefix) => {
459                write_with_vendor_prefix(dest, vendorPrefix, "native-anonymous")
460            }
461
462            Self::only_whitespace(ref vendorPrefix) => {
463                write_with_vendor_prefix(dest, vendorPrefix, "only-whitespace")
464            }
465
466            Self::submit_invalid(ref vendorPrefix) => {
467                write_with_vendor_prefix(dest, vendorPrefix, "submit-invalid")
468            }
469
470            Self::suppressed(ref vendorPrefix) => {
471                write_with_vendor_prefix(dest, vendorPrefix, "suppressed")
472            }
473
474            Self::system_metric(ref vendorPrefix, ref value) => {
475                write_with_vendor_prefix_value(
476                    dest,
477                    vendorPrefix,
478                    "system-metric",
479                    value,
480                )
481            }
482
483            Self::tree_cell(ref vendorPrefix) => {
484                write_with_vendor_prefix(dest, vendorPrefix, "tree-cell")
485            }
486
487            Self::tree_cell_text(ref vendorPrefix, ref value) => {
488                write_with_vendor_prefix_value(
489                    dest,
490                    vendorPrefix,
491                    "tree-cell-text",
492                    value,
493                )
494            }
495
496            Self::tree_checkbox(ref vendorPrefix) => {
497                write_with_vendor_prefix(dest, vendorPrefix, "tree-checkbox")
498            }
499
500            Self::tree_column(ref vendorPrefix) => {
501                write_with_vendor_prefix(dest, vendorPrefix, "tree-column")
502            }
503
504            Self::tree_drop_feedback(ref vendorPrefix) => {
505                write_with_vendor_prefix(
506                    dest,
507                    vendorPrefix,
508                    "tree-drop-feedback",
509                )
510            }
511
512            Self::tree_image(ref vendorPrefix) => {
513                write_with_vendor_prefix(dest, vendorPrefix, "tree-image")
514            }
515
516            Self::tree_indentation(ref vendorPrefix) => {
517                write_with_vendor_prefix(dest, vendorPrefix, "tree-indentation")
518            }
519
520            Self::tree_line(ref vendorPrefix) => {
521                write_with_vendor_prefix(dest, vendorPrefix, "tree-line")
522            }
523
524            Self::tree_progressmeter(ref vendorPrefix) => {
525                write_with_vendor_prefix(
526                    dest,
527                    vendorPrefix,
528                    "tree-progressmeter",
529                )
530            }
531
532            Self::tree_row(ref vendorPrefix, ref value) => {
533                write_with_vendor_prefix_value(
534                    dest,
535                    vendorPrefix,
536                    "tree-row",
537                    value,
538                )
539            }
540
541            Self::tree_separator(ref vendorPrefix) => {
542                write_with_vendor_prefix(dest, vendorPrefix, "tree-separator")
543            }
544
545            Self::tree_twisty(ref vendorPrefix) => {
546                write_with_vendor_prefix(dest, vendorPrefix, "tree-twisty")
547            }
548
549            Self::ui_invalid(ref vendorPrefix) => {
550                write_with_vendor_prefix(dest, vendorPrefix, "ui-invalid")
551            }
552
553            Self::ui_valid(ref vendorPrefix) => {
554                write_with_vendor_prefix(dest, vendorPrefix, "ui-valid")
555            }
556
557            Self::user_disabled(ref vendorPrefix) => {
558                write_with_vendor_prefix(dest, vendorPrefix, "user-disabled")
559            }
560
561            Self::window_inactive(ref vendorPrefix) => {
562                write_with_vendor_prefix(dest, vendorPrefix, "window-inactive")
563            }
564
565            Self::autofill(ref vendorPrefix) => {
566                write_with_vendor_prefix(dest, vendorPrefix, "autofill")
567            }
568        }
569    }
570}
571
572impl NonTreeStructuralPseudoClass {
573    /// Returns true if the evaluation of the pseudo-class depends on the element's attributes.
574    pub fn is_attr_based(&self) -> bool {
575        use self::NonTreeStructuralPseudoClass::*;
576
577        matches!(*self, lang(..))
578    }
579
580    /// <https://drafts.csswg.org/selectors-4/#useraction-pseudos>
581    ///
582    /// We intentionally skip the link-related ones.
583    pub fn is_safe_user_action_state(&self) -> bool {
584        use self::NonTreeStructuralPseudoClass::*;
585
586        matches!(*self, active | focus | hover)
587    }
588
589    #[inline(always)]
590    fn applyVendorPrefix(
591        pseudoClassName: VendorPrefixablePseudoClassName,
592        applyVendorPrefixToPseudoClasses: &HashMap<
593            VendorPrefixablePseudoClassName,
594            VendorPrefix,
595        >,
596    ) -> Option<VendorPrefix> {
597        applyVendorPrefixToPseudoClasses
598            .get(&pseudoClassName)
599            .cloned()
600    }
601
602    //noinspection SpellCheckingInspection
603    #[inline(always)]
604    pub(crate) fn parse_without_arguments<'i>(
605        applyVendorPrefixToPseudoClasses: &HashMap<
606            VendorPrefixablePseudoClassName,
607            VendorPrefix,
608        >,
609        name: CowRcStr<'i>,
610    ) -> Result<Self, ParseError<'i, CustomParseError<'i>>> {
611        match_ignore_ascii_case! {
612            &name,
613
614            "active" => Ok(Self::active),
615
616            "any-link" => Ok(Self::any_link(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::any_link, applyVendorPrefixToPseudoClasses))),
617
618            "-moz-any-link" => Ok(Self::any_link(Some(moz))),
619
620            "-webkit-any-link" => Ok(Self::any_link(Some(webkit))),
621
622            "checked" => Ok(Self::checked),
623
624            "default" => Ok(Self::default),
625
626            "disabled" => Ok(Self::disabled),
627
628            "enabled" => Ok(Self::enabled),
629
630            "first" => Ok(Self::first),
631
632            "focus" => Ok(Self::focus),
633
634            "focus-within" => Ok(Self::focus_within),
635
636            "fullscreen" => Ok(Self::fullscreen(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::fullscreen, applyVendorPrefixToPseudoClasses))),
637
638            "-ms-fullscreen" => Ok(Self::fullscreen(Some(ms))),
639
640            "-moz-full-screen" => Ok(Self::fullscreen(Some(moz))),
641
642            "-webkit-full-screen" => Ok(Self::fullscreen(Some(webkit))),
643
644            "hover" => Ok(Self::hover),
645
646            "indeterminate" => Ok(Self::indeterminate),
647
648            "in-range" => Ok(Self::in_range),
649
650            "invalid" => Ok(Self::invalid),
651
652            "left" => Ok(Self::left),
653
654            "link" => Ok(Self::link),
655
656            "optional" => Ok(Self::optional),
657
658            "out-of-range" => Ok(Self::out_of_range),
659
660            "placeholder-shown" => Ok(Self::placeholder_shown(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::placeholder_shown, applyVendorPrefixToPseudoClasses))),
661
662            "-moz-placeholder-shown" => Ok(Self::placeholder_shown(Some(moz))),
663
664            // See https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-placeholder
665            "-moz-placeholder" => Ok(Self::placeholder_shown(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::placeholder_shown, applyVendorPrefixToPseudoClasses))),
666
667            "read-only" => Ok(Self::read_only(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::read_only, applyVendorPrefixToPseudoClasses))),
668
669            "-moz-read-only" => Ok(Self::read_only(Some(moz))),
670
671            "read-write" => Ok(Self::read_write(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::read_write, applyVendorPrefixToPseudoClasses))),
672
673            "-moz-read-write" => Ok(Self::read_write(Some(moz))),
674
675            "required" => Ok(Self::required),
676
677            "right" => Ok(Self::right),
678
679            "scope" => Err(ParseError::from(CustomParseError::NonTreeStructuralPseudoClassScopeIsObsoleteAsOfFirefox55)),
680
681            "target" => Ok(Self::target),
682
683            "valid" => Ok(Self::valid),
684
685            "visited" => Ok(Self::visited),
686
687
688            // -servo-only
689
690            "-servo-non-zero-border" => Ok(Self::non_zero_border(Some(servo))),
691
692
693            // -moz- only
694
695            "-moz-broken" => Ok(Self::broken(Some(moz))),
696
697            "-moz-drag-over" => Ok(Self::drag_over(Some(moz))),
698
699            "-moz-first-node" => Ok(Self::first_node(Some(moz))),
700
701            "-moz-focusring" => Ok(Self::focusring(Some(moz))),
702
703            "-moz-full-screen-ancestor" => Ok(Self::full_screen_ancestor(Some(moz))),
704
705            "-moz-handler-blocked" => Ok(Self::handler_blocked(Some(moz))),
706
707            "-moz-handler-crashed" => Ok(Self::handler_crashed(Some(moz))),
708
709            "-moz-handler-disabled" => Ok(Self::handler_disabled(Some(moz))),
710
711            "-moz-last-node" => Ok(Self::last_node(Some(moz))),
712
713            "-moz-list-bullet" => Ok(Self::list_bullet(Some(moz))),
714
715            "-moz-list-number" => Ok(Self::list_number(Some(moz))),
716
717            "-moz-loading" => Ok(Self::loading(Some(moz))),
718
719            "-moz-lwtheme" => Ok(Self::lwtheme(Some(moz))),
720
721            "-moz-lwtheme-brighttext" => Ok(Self::lwtheme_brighttext(Some(moz))),
722
723            "-moz-lwtheme-darktext" => Ok(Self::lwtheme_darktext(Some(moz))),
724
725            "-moz-native-anonymous" => Ok(Self::native_anonymous(Some(moz))),
726
727            "-moz-only-whitespace" => Ok(Self::only_whitespace(Some(moz))),
728
729            "-moz-submit-invalid" => Ok(Self::submit_invalid(Some(moz))),
730
731            "-moz-suppressed" => Ok(Self::suppressed(Some(moz))),
732
733            "-moz-tree-cell" => Ok(Self::tree_cell(Some(moz))),
734
735            "-moz-tree-checkbox" => Ok(Self::tree_checkbox(Some(moz))),
736
737            "-moz-tree-column" => Ok(Self::tree_column(Some(moz))),
738
739            "-moz-tree-drop-feedback" => Ok(Self::tree_drop_feedback(Some(moz))),
740
741            "-moz-tree-image" => Ok(Self::tree_image(Some(moz))),
742
743            "-moz-tree-indentation" => Ok(Self::tree_indentation(Some(moz))),
744
745            "-moz-tree-line" => Ok(Self::tree_line(Some(moz))),
746
747            "-moz-tree-progressmeter" => Ok(Self::tree_progressmeter(Some(moz))),
748
749            "-moz-tree-separator" => Ok(Self::tree_separator(Some(moz))),
750
751            "-moz-tree-twisty" => Ok(Self::tree_twisty(Some(moz))),
752
753            "-moz-ui-invalid" => Ok(Self::ui_invalid(Some(moz))),
754
755            "-moz-ui-valid" => Ok(Self::ui_valid(Some(moz))),
756
757            "-moz-user-disabled" => Ok(Self::user_disabled(Some(moz))),
758
759            "-moz-window-inactive" => Ok(Self::window_inactive(Some(moz))),
760
761
762            // -webkit- only, with potential Mozilla support coming
763
764            "-webkit-autofill" => Ok(Self::autofill(Some(webkit))),
765
766            "-moz-autofill" => Ok(Self::autofill(Some(moz))),
767
768
769            _ => Err(ParseError::from(CustomParseError::UnsupportedPseudoClassOrElement(name.to_string()))),
770        }
771    }
772
773    #[inline(always)]
774    pub(crate) fn parse_with_arguments<'i, 't>(
775        applyVendorPrefixToPseudoClasses: &HashMap<
776            VendorPrefixablePseudoClassName,
777            VendorPrefix,
778        >,
779        name: CowRcStr<'i>,
780        input: &mut Parser<'i, 't>,
781        ourSelectorParser: &OurSelectorParser,
782    ) -> Result<Self, ParseError<'i, CustomParseError<'i>>> {
783        use self::{NonTreeStructuralPseudoClass::*, VendorPrefix::*};
784
785        match_ignore_ascii_case! {
786            &name,
787
788            "any" => Ok(any(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::any, applyVendorPrefixToPseudoClasses), Self::parse_any(input, ourSelectorParser)?)),
789
790            "-moz-any" => Ok(any(Some(moz), Self::parse_any(input, ourSelectorParser)?)),
791
792            "-webkit-any" => Ok(any(Some(webkit), Self::parse_any(input, ourSelectorParser)?)),
793
794            "dir" => Ok(dir(Self::applyVendorPrefix(VendorPrefixablePseudoClassName::dir, applyVendorPrefixToPseudoClasses), Self::parse_text_directionality(input)?)),
795
796            "-moz-dir" => Ok(dir(Some(moz), Self::parse_text_directionality(input)?)),
797
798            "lang" => Ok(lang(Self::parse_lang(input)?)),
799
800            "where" => Ok(Self::where_(ourSelectorParser.parse_internal(input, OurSelectorExt::is_false_if_any_selector_is_simple_and_only_uses_the_descendant_combinator)?)),
801
802            "is" => Ok(Self::is(ourSelectorParser.parse_internal(input, OurSelectorExt::is_false_if_any_selector_is_simple_and_only_uses_the_descendant_combinator)?)),
803
804            // -servo- only
805
806            "-servo-case-sensitive-type-attr" => Ok(case_sensitive_type_attr(Some(servo), Atom::from(input.expect_ident()?))),
807
808
809            // -moz- only
810
811            "-moz-locale-dir" => Ok(locale_dir(Some(moz), Self::parse_text_directionality(input)?)),
812
813            "-moz-system-metric" => Ok(system_metric(Some(moz), Self::parse_system_metric(input)?)),
814
815            "-moz-tree-cell-text" => Ok(tree_cell_text(Some(moz), Self::parse_tree_hover(input)?)),
816
817            "-moz-tree-row" => Ok(tree_row(Some(moz), Self::parse_tree_hover(input)?)),
818
819
820            _ => Err(ParseError::from(CustomParseError::UnsupportedPseudoClassOrElement(name.to_string()))),
821        }
822    }
823
824    #[inline(always)]
825    pub(crate) fn parse_any<'i, 't>(
826        input: &mut Parser<'i, 't>,
827        ourSelectorParser: &OurSelectorParser,
828    ) -> Result<DeduplicatedSelectors, ParseError<'i, CustomParseError<'i>>>
829    {
830        ourSelectorParser
831            .parse_internal(
832                input,
833                OurSelectorExt::is_false_if_any_selector_is_simple_and_only_uses_the_descendant_combinator
834            )
835    }
836
837    #[inline(always)]
838    pub(crate) fn parse_text_directionality<'i, 't>(
839        input: &mut Parser<'i, 't>,
840    ) -> Result<TextDirectionality, ParseError<'i, CustomParseError<'i>>> {
841        TextDirectionality::parse(input)
842    }
843
844    #[inline(always)]
845    pub(crate) fn parse_system_metric<'i, 't>(
846        input: &mut Parser<'i, 't>,
847    ) -> Result<SystemMetric, ParseError<'i, CustomParseError<'i>>> {
848        SystemMetric::parse(input)
849    }
850
851    #[inline(always)]
852    pub(crate) fn parse_tree_hover<'i, 't>(
853        input: &mut Parser<'i, 't>,
854    ) -> Result<TreeHover, ParseError<'i, CustomParseError<'i>>> {
855        TreeHover::parse(input)
856    }
857
858    #[inline(always)]
859    pub(crate) fn parse_lang<'i, 't>(
860        input: &mut Parser<'i, 't>,
861    ) -> Result<LanguageRanges, ParseError<'i, CustomParseError<'i>>> {
862        // the :lang() pseudo-class represents an element that is in one of the languages listed in its argument. It accepts a comma-separated list of one or more language ranges as its argument. Each language range in :lang() must be a valid CSS <ident> or <string>. (Language ranges containing asterisks, for example, must be quoted as strings.)
863        let languages = input.parse_comma_separated(|input| {
864            Ok(LanguageRange(Atom::from(
865                input.expect_ident_or_string()?.as_ref(),
866            )))
867        })?;
868        Ok(LanguageRanges(languages))
869        //.map(LanguageRanges)
870    }
871}