1
//! Representation of CSS types, and the CSS parsing and matching engine.
2
//!
3
//! # Terminology
4
//!
5
//! Consider a CSS **stylesheet** like this:
6
//!
7
//! ```css
8
//! @import url("another.css");
9
//!
10
//! foo, .bar {
11
//!         fill: red;
12
//!         stroke: green;
13
//! }
14
//!
15
//! #baz { stroke-width: 42; }
16
//! ```
17
//! The example contains three **rules**, the first one is an **at-rule*,
18
//! the other two are **qualified rules**.
19
//!
20
//! Each rule is made of two parts, a **prelude** and an optional **block**
21
//! The prelude is the part until the first `{` or until `;`, depending on
22
//! whether a block is present.  The block is the part between curly braces.
23
//!
24
//! Let's look at each rule:
25
//!
26
//! `@import` is an **at-rule**.  This rule has a prelude, but no block.
27
//! There are other at-rules like `@media` and some of them may have a block,
28
//! but librsvg doesn't support those yet.
29
//!
30
//! The prelude of the following rule is `foo, .bar`.
31
//! It is a **selector list** with two **selectors**, one for
32
//! `foo` elements and one for elements that have the `bar` class.
33
//!
34
//! The content of the block between `{}` for a qualified rule is a
35
//! **declaration list**.  The block of the first qualified rule contains two
36
//! **declarations**, one for the `fill` **property** and one for the
37
//! `stroke` property.
38
//!
39
//! After the first qualified rule, we have a second qualified rule with
40
//! a single selector for the `#baz` id, with a single declaration for the
41
//! `stroke-width` property.
42
//!
43
//! # Helper crates we use
44
//!
45
//! * `cssparser` crate as a CSS tokenizer, and some utilities to
46
//!   parse CSS rules and declarations.
47
//!
48
//! * `selectors` crate for the representation of selectors and
49
//!   selector lists, and for the matching engine.
50
//!
51
//! Both crates provide very generic implementations of their concepts,
52
//! and expect the caller to provide implementations of various traits,
53
//! and to provide types that represent certain things.
54
//!
55
//! For example, `cssparser` expects one to provide representations of
56
//! the following types:
57
//!
58
//! * A parsed CSS rule.  For `fill: blue;` we have
59
//!   `ParsedProperty::Fill(...)`.
60
//!
61
//! * A parsed selector list; we use `SelectorList` from the
62
//!   `selectors` crate.
63
//!
64
//! In turn, the `selectors` crate needs a way to navigate and examine
65
//! one's implementation of an element tree.  We provide `impl
66
//! selectors::Element for RsvgElement` for this.  This implementation
67
//! has methods like "does this element have the id `#foo`", or "give
68
//! me the next sibling element".
69
//!
70
//! Finally, the matching engine ties all of this together with
71
//! `matches_selector()`.  This takes an opaque representation of an
72
//! element, plus a selector, and returns a bool.  We iterate through
73
//! the rules in the stylesheets and gather the matches; then sort the
74
//! matches by specificity and apply the result to each element.
75

            
76
use cssparser::{
77
    self, match_ignore_ascii_case, parse_important, AtRuleParser, BasicParseErrorKind, CowRcStr,
78
    DeclarationParser, Parser, ParserInput, ParserState, QualifiedRuleParser, RuleBodyItemParser,
79
    RuleBodyParser, SourceLocation, StyleSheetParser, ToCss,
80
};
81
use data_url::mime::Mime;
82
use language_tags::LanguageTag;
83
use markup5ever::{self, ns, Namespace, QualName};
84
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
85
use selectors::matching::{
86
    ElementSelectorFlags, IgnoreNthChildForInvalidation, MatchingContext, MatchingMode,
87
    NeedsSelectorFlags, QuirksMode,
88
};
89
use selectors::parser::ParseRelative;
90
use selectors::{NthIndexCache, OpaqueElement, SelectorImpl, SelectorList};
91
use std::cmp::Ordering;
92
use std::fmt;
93
use std::str;
94
use std::str::FromStr;
95

            
96
use crate::element::Element;
97
use crate::error::*;
98
use crate::io::{self, BinaryData};
99
use crate::node::{Node, NodeBorrow, NodeCascade};
100
use crate::properties::{parse_value, ComputedValues, ParseAs, ParsedProperty};
101
use crate::rsvg_log;
102
use crate::session::Session;
103
use crate::url_resolver::{AllowedUrl, UrlResolver};
104

            
105
/// A parsed CSS declaration
106
///
107
/// For example, in the declaration `fill: green !important`, the
108
/// `prop_name` would be `fill`, the `property` would be
109
/// `ParsedProperty::Fill(...)` with the green value, and `important`
110
/// would be `true`.
111
pub struct Declaration {
112
    pub prop_name: QualName,
113
    pub property: ParsedProperty,
114
    pub important: bool,
115
}
116

            
117
/// This enum represents the fact that a rule body can be either a
118
/// declaration or a nested rule.
119
pub enum RuleBodyItem {
120
    Decl(Declaration),
121
    #[allow(dead_code)] // We don't support nested rules yet
122
    Rule(Rule),
123
}
124

            
125
/// Dummy struct required to use `cssparser::DeclarationListParser`
126
///
127
/// It implements `cssparser::DeclarationParser`, which knows how to parse
128
/// the property/value pairs from a CSS declaration.
129
pub struct DeclParser;
130

            
131
impl<'i> DeclarationParser<'i> for DeclParser {
132
    type Declaration = RuleBodyItem;
133
    type Error = ValueErrorKind;
134

            
135
    /// Parses a CSS declaration like `name: input_value [!important]`
136
731104
    fn parse_value<'t>(
137
731104
        &mut self,
138
731104
        name: CowRcStr<'i>,
139
731104
        input: &mut Parser<'i, 't>,
140
731104
    ) -> Result<RuleBodyItem, cssparser::ParseError<'i, Self::Error>> {
141
731104
        let prop_name = QualName::new(None, ns!(), markup5ever::LocalName::from(name.as_ref()));
142
731104
        let property = parse_value(&prop_name, input, ParseAs::Property)?;
143

            
144
633558
        let important = input.try_parse(parse_important).is_ok();
145
633558

            
146
633558
        Ok(RuleBodyItem::Decl(Declaration {
147
633558
            prop_name,
148
633558
            property,
149
633558
            important,
150
633558
        }))
151
731104
    }
152
}
153

            
154
// cssparser's DeclarationListParser requires this; we just use the dummy
155
// implementations from cssparser itself.  We may want to provide a real
156
// implementation in the future, although this may require keeping track of the
157
// CSS parsing state like Servo does.
158
impl<'i> AtRuleParser<'i> for DeclParser {
159
    type Prelude = ();
160
    type AtRule = RuleBodyItem;
161
    type Error = ValueErrorKind;
162
}
163

            
164
/// We need this dummy implementation as well.
165
impl<'i> QualifiedRuleParser<'i> for DeclParser {
166
    type Prelude = ();
167
    type QualifiedRule = RuleBodyItem;
168
    type Error = ValueErrorKind;
169
}
170

            
171
impl<'i> RuleBodyItemParser<'i, RuleBodyItem, ValueErrorKind> for DeclParser {
172
    /// We want to parse declarations.
173
731123
    fn parse_declarations(&self) -> bool {
174
731123
        true
175
731123
    }
176

            
177
    /// We don't wanto parse qualified rules though.
178
97584
    fn parse_qualified(&self) -> bool {
179
97584
        false
180
97584
    }
181
}
182

            
183
/// Struct to implement cssparser::QualifiedRuleParser and cssparser::AtRuleParser
184
pub struct RuleParser {
185
    session: Session,
186
}
187

            
188
/// Errors from the CSS parsing process
189
#[allow(dead_code)] // looks like we are not actually using this yet?
190
#[derive(Debug)]
191
pub enum ParseErrorKind<'i> {
192
    Selector(selectors::parser::SelectorParseErrorKind<'i>),
193
}
194

            
195
impl<'i> From<selectors::parser::SelectorParseErrorKind<'i>> for ParseErrorKind<'i> {
196
    fn from(e: selectors::parser::SelectorParseErrorKind<'_>) -> ParseErrorKind<'_> {
197
        ParseErrorKind::Selector(e)
198
    }
199
}
200

            
201
/// A CSS qualified rule (or ruleset)
202
pub struct QualifiedRule {
203
    selectors: SelectorList<Selector>,
204
    declarations: Vec<Declaration>,
205
}
206

            
207
/// Prelude of at-rule used in the AtRuleParser.
208
pub enum AtRulePrelude {
209
    Import(String),
210
}
211

            
212
/// A CSS at-rule (or ruleset)
213
pub enum AtRule {
214
    Import(String),
215
}
216

            
217
/// A CSS rule (or ruleset)
218
pub enum Rule {
219
    AtRule(AtRule),
220
    QualifiedRule(QualifiedRule),
221
}
222

            
223
// Required to implement the `Prelude` associated type in `cssparser::QualifiedRuleParser`
224
impl<'i> selectors::Parser<'i> for RuleParser {
225
    type Impl = Selector;
226
    type Error = ParseErrorKind<'i>;
227

            
228
46572
    fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
229
46572
        Some(ns!(svg))
230
46572
    }
231

            
232
    fn namespace_for_prefix(
233
        &self,
234
        _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
235
    ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
236
        // FIXME: Do we need to keep a lookup table extracted from libxml2's
237
        // XML namespaces?
238
        //
239
        // Or are CSS namespaces completely different, declared elsewhere?
240
        None
241
    }
242
38
    fn parse_non_ts_pseudo_class(
243
38
        &self,
244
38
        location: SourceLocation,
245
38
        name: CowRcStr<'i>,
246
38
    ) -> Result<NonTSPseudoClass, cssparser::ParseError<'i, Self::Error>> {
247
38
        match &*name {
248
38
            "link" => Ok(NonTSPseudoClass::Link),
249
            "visited" => Ok(NonTSPseudoClass::Visited),
250
            _ => Err(location.new_custom_error(
251
                selectors::parser::SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
252
            )),
253
        }
254
38
    }
255
114
    fn parse_non_ts_functional_pseudo_class(
256
114
        &self,
257
114
        name: CowRcStr<'i>,
258
114
        arguments: &mut Parser<'i, '_>,
259
114
    ) -> Result<NonTSPseudoClass, cssparser::ParseError<'i, Self::Error>> {
260
114
        match &*name {
261
114
            "lang" => {
262
                // Comma-separated lists of languages are a Selectors 4 feature,
263
                // but a pretty stable one that hasn't changed in a long time.
264
133
                let tags = arguments.parse_comma_separated(|arg| {
265
133
                    let language_tag = arg.expect_ident_or_string()?.clone();
266
133
                    LanguageTag::from_str(&language_tag).map_err(|_| {
267
                        arg.new_custom_error(selectors::parser::SelectorParseErrorKind::UnsupportedPseudoClassOrElement(language_tag))
268
133
                    })
269
133
                })?;
270
114
                arguments.expect_exhausted()?;
271
114
                Ok(NonTSPseudoClass::Lang(tags))
272
            }
273
            _ => Err(arguments.new_custom_error(
274
                selectors::parser::SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
275
            )),
276
        }
277
114
    }
278
}
279

            
280
// `cssparser::StyleSheetParser` is a struct which requires that we provide a type that
281
// implements `cssparser::QualifiedRuleParser` and `cssparser::AtRuleParser`.
282
//
283
// In turn, `cssparser::QualifiedRuleParser` requires that we
284
// implement a way to parse the `Prelude` of a ruleset or rule.  For
285
// example, in this ruleset:
286
//
287
// ```css
288
// foo, .bar { fill: red; stroke: green; }
289
// ```
290
//
291
// The prelude is the selector list with the `foo` and `.bar` selectors.
292
//
293
// The `parse_prelude` method just uses `selectors::SelectorList`.  This
294
// is what requires the `impl selectors::Parser for RuleParser`.
295
//
296
// Next, the `parse_block` method takes an already-parsed prelude (a selector list),
297
// and tries to parse the block between braces.  It creates a `Rule` out of
298
// the selector list and the declaration list.
299
impl<'i> QualifiedRuleParser<'i> for RuleParser {
300
    type Prelude = SelectorList<Selector>;
301
    type QualifiedRule = Rule;
302
    type Error = ValueErrorKind;
303

            
304
8743
    fn parse_prelude<'t>(
305
8743
        &mut self,
306
8743
        input: &mut Parser<'i, 't>,
307
8743
    ) -> Result<Self::Prelude, cssparser::ParseError<'i, Self::Error>> {
308
8743
        SelectorList::parse(self, input, ParseRelative::No).map_err(|e| ParseError {
309
            kind: cssparser::ParseErrorKind::Custom(ValueErrorKind::parse_error(
310
                "Could not parse selector",
311
            )),
312
            location: e.location,
313
8743
        })
314
8743
    }
315

            
316
8743
    fn parse_block<'t>(
317
8743
        &mut self,
318
8743
        prelude: Self::Prelude,
319
8743
        _start: &ParserState,
320
8743
        input: &mut Parser<'i, 't>,
321
8743
    ) -> Result<Self::QualifiedRule, cssparser::ParseError<'i, Self::Error>> {
322
8743
        let declarations = RuleBodyParser::<_, _, Self::Error>::new(input, &mut DeclParser)
323
9712
            .filter_map(|r| match r {
324
9712
                Ok(RuleBodyItem::Decl(decl)) => Some(decl),
325
                Ok(RuleBodyItem::Rule(_)) => None,
326
19
                Err(e) => {
327
19
                    rsvg_log!(self.session, "Invalid declaration; ignoring: {:?}", e);
328
19
                    None
329
                }
330
9731
            })
331
8743
            .collect();
332
8743

            
333
8743
        Ok(Rule::QualifiedRule(QualifiedRule {
334
8743
            selectors: prelude,
335
8743
            declarations,
336
8743
        }))
337
8743
    }
338
}
339

            
340
// Required by `cssparser::StyleSheetParser`.
341
//
342
// This only handles the `@import` at-rule.
343
impl<'i> AtRuleParser<'i> for RuleParser {
344
    type Prelude = AtRulePrelude;
345
    type AtRule = Rule;
346
    type Error = ValueErrorKind;
347

            
348
    #[allow(clippy::type_complexity)]
349
76
    fn parse_prelude<'t>(
350
76
        &mut self,
351
76
        name: CowRcStr<'i>,
352
76
        input: &mut Parser<'i, 't>,
353
76
    ) -> Result<Self::Prelude, cssparser::ParseError<'i, Self::Error>> {
354
76
        match_ignore_ascii_case! {
355
76
            &name,
356
76

            
357
76
            // FIXME: at the moment we ignore media queries
358
76

            
359
76
            "import" => {
360
38
                let url = input.expect_url_or_string()?.as_ref().to_owned();
361
38
                Ok(AtRulePrelude::Import(url))
362
            },
363

            
364
38
            _ => Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name))),
365
        }
366
76
    }
367

            
368
38
    fn rule_without_block(
369
38
        &mut self,
370
38
        prelude: Self::Prelude,
371
38
        _start: &ParserState,
372
38
    ) -> Result<Self::AtRule, ()> {
373
38
        let AtRulePrelude::Import(url) = prelude;
374
38
        Ok(Rule::AtRule(AtRule::Import(url)))
375
38
    }
376

            
377
    // When we implement at-rules with blocks, implement the trait's parse_block() method here.
378
}
379

            
380
/// Dummy type required by the SelectorImpl trait.
381
#[allow(clippy::upper_case_acronyms)]
382
#[derive(Clone, Debug, Eq, PartialEq)]
383
pub enum NonTSPseudoClass {
384
    Link,
385
    Visited,
386
    Lang(Vec<LanguageTag>),
387
}
388

            
389
impl ToCss for NonTSPseudoClass {
390
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
391
    where
392
        W: fmt::Write,
393
    {
394
        match self {
395
            NonTSPseudoClass::Link => write!(dest, "link"),
396
            NonTSPseudoClass::Visited => write!(dest, "visited"),
397
            NonTSPseudoClass::Lang(lang) => write!(
398
                dest,
399
                "lang(\"{}\")",
400
                lang.iter()
401
                    .map(ToString::to_string)
402
                    .collect::<Vec<_>>()
403
                    .join("\",\"")
404
            ),
405
        }
406
    }
407
}
408

            
409
impl selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
410
    type Impl = Selector;
411

            
412
    fn is_active_or_hover(&self) -> bool {
413
        false
414
    }
415

            
416
    fn is_user_action_state(&self) -> bool {
417
        false
418
    }
419
}
420

            
421
/// Dummy type required by the SelectorImpl trait
422
#[derive(Clone, Debug, Eq, PartialEq)]
423
pub struct PseudoElement;
424

            
425
impl ToCss for PseudoElement {
426
    fn to_css<W>(&self, _dest: &mut W) -> fmt::Result
427
    where
428
        W: fmt::Write,
429
    {
430
        Ok(())
431
    }
432
}
433

            
434
impl selectors::parser::PseudoElement for PseudoElement {
435
    type Impl = Selector;
436
}
437

            
438
/// Holds all the types for the SelectorImpl trait
439
#[derive(Debug, Clone)]
440
pub struct Selector;
441

            
442
/// Wrapper for attribute values.
443
///
444
/// We use a newtype because the associated type Selector::AttrValue
445
/// must implement `From<&str>` and `ToCss`, which are foreign traits.
446
///
447
/// The `derive` requirements come from the `selectors` crate.
448
#[derive(Clone, PartialEq, Eq)]
449
pub struct AttributeValue(String);
450

            
451
impl From<&str> for AttributeValue {
452
247
    fn from(s: &str) -> AttributeValue {
453
247
        AttributeValue(s.to_owned())
454
247
    }
455
}
456

            
457
impl ToCss for AttributeValue {
458
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
459
    where
460
        W: fmt::Write,
461
    {
462
        use std::fmt::Write;
463

            
464
        write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)
465
    }
466
}
467

            
468
impl AsRef<str> for AttributeValue {
469
1121
    fn as_ref(&self) -> &str {
470
1121
        self.0.as_ref()
471
1121
    }
472
}
473

            
474
/// Wrapper for identifier values.
475
///
476
/// Used to implement `ToCss` on the `LocalName` foreign type.
477
#[derive(Clone, PartialEq, Eq)]
478
pub struct Identifier(markup5ever::LocalName);
479

            
480
impl From<&str> for Identifier {
481
2000
    fn from(s: &str) -> Identifier {
482
2000
        Identifier(markup5ever::LocalName::from(s))
483
2000
    }
484
}
485

            
486
impl ToCss for Identifier {
487
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
488
    where
489
        W: fmt::Write,
490
    {
491
        cssparser::serialize_identifier(&self.0, dest)
492
    }
493
}
494

            
495
/// Wrapper for local names.
496
///
497
/// Used to implement `ToCss` on the `LocalName` foreign type.
498
#[derive(Clone, PartialEq, Eq)]
499
pub struct LocalName(markup5ever::LocalName);
500

            
501
impl From<&str> for LocalName {
502
81703
    fn from(s: &str) -> LocalName {
503
81703
        LocalName(markup5ever::LocalName::from(s))
504
81703
    }
505
}
506

            
507
impl ToCss for LocalName {
508
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
509
    where
510
        W: fmt::Write,
511
    {
512
        cssparser::serialize_identifier(&self.0, dest)
513
    }
514
}
515

            
516
/// Wrapper for namespace prefixes.
517
///
518
/// Used to implement `ToCss` on the `markup5ever::Prefix` foreign type.
519
#[derive(Clone, Default, PartialEq, Eq)]
520
pub struct NamespacePrefix(markup5ever::Prefix);
521

            
522
impl From<&str> for NamespacePrefix {
523
    fn from(s: &str) -> NamespacePrefix {
524
        NamespacePrefix(markup5ever::Prefix::from(s))
525
    }
526
}
527

            
528
impl ToCss for NamespacePrefix {
529
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
530
    where
531
        W: fmt::Write,
532
    {
533
        cssparser::serialize_identifier(&self.0, dest)
534
    }
535
}
536

            
537
impl SelectorImpl for Selector {
538
    type ExtraMatchingData<'a> = ();
539
    type AttrValue = AttributeValue;
540
    type Identifier = Identifier;
541
    type LocalName = LocalName;
542
    type NamespaceUrl = Namespace;
543
    type NamespacePrefix = NamespacePrefix;
544
    type BorrowedNamespaceUrl = Namespace;
545
    type BorrowedLocalName = LocalName;
546
    type NonTSPseudoClass = NonTSPseudoClass;
547
    type PseudoElement = PseudoElement;
548
}
549

            
550
/// Newtype wrapper around `Node` so we can implement [`selectors::Element`] for it.
551
///
552
/// `Node` is an alias for [`rctree::Node`], so we can't implement
553
/// `selectors::Element` directly on it.  We implement it on the
554
/// `RsvgElement` wrapper instead.
555
#[derive(Clone, PartialEq)]
556
pub struct RsvgElement(Node);
557

            
558
impl From<Node> for RsvgElement {
559
14808
    fn from(n: Node) -> RsvgElement {
560
14808
        RsvgElement(n)
561
14808
    }
562
}
563

            
564
impl fmt::Debug for RsvgElement {
565
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566
        write!(f, "{}", self.0.borrow())
567
    }
568
}
569

            
570
// The selectors crate uses this to examine our tree of elements.
571
impl selectors::Element for RsvgElement {
572
    type Impl = Selector;
573

            
574
    /// Converts self into an opaque representation.
575
361
    fn opaque(&self) -> OpaqueElement {
576
361
        // The `selectors` crate uses this value just for pointer comparisons, to answer
577
361
        // the question, "is this element the same as that one?".  So, we'll give it a
578
361
        // reference to our actual node's data, i.e. skip over whatever wrappers there
579
361
        // are in rctree.
580
361
        //
581
361
        // We use an explicit type here to make it clear what the type is; otherwise you
582
361
        // may be fooled by the fact that borrow_element() returns a Ref<Element>, not a
583
361
        // plain reference: &Ref<T> is transient and would get dropped at the end of this
584
361
        // function, but we want something long-lived.
585
361
        let element: &Element = &self.0.borrow_element();
586
361
        OpaqueElement::new::<Element>(element)
587
361
    }
588

            
589
14919
    fn parent_element(&self) -> Option<Self> {
590
14919
        self.0.parent().map(|n| n.into())
591
14919
    }
592

            
593
    /// Whether the parent node of this element is a shadow root.
594
2280
    fn parent_node_is_shadow_root(&self) -> bool {
595
2280
        // unsupported
596
2280
        false
597
2280
    }
598

            
599
    /// The host of the containing shadow root, if any.
600
    fn containing_shadow_host(&self) -> Option<Self> {
601
        // unsupported
602
        None
603
    }
604

            
605
    /// Whether we're matching on a pseudo-element.
606
    fn is_pseudo_element(&self) -> bool {
607
        // unsupported
608
        false
609
    }
610

            
611
    /// Skips non-element nodes
612
3347
    fn prev_sibling_element(&self) -> Option<Self> {
613
3347
        let mut sibling = self.0.previous_sibling();
614

            
615
6675
        while let Some(ref sib) = sibling {
616
5268
            if sib.is_element() {
617
1940
                return sibling.map(|n| n.into());
618
3328
            }
619
3328

            
620
3328
            sibling = sib.previous_sibling();
621
        }
622

            
623
1407
        None
624
3347
    }
625

            
626
    /// Skips non-element nodes
627
383
    fn next_sibling_element(&self) -> Option<Self> {
628
383
        let mut sibling = self.0.next_sibling();
629

            
630
766
        while let Some(ref sib) = sibling {
631
613
            if sib.is_element() {
632
230
                return sibling.map(|n| n.into());
633
383
            }
634
383

            
635
383
            sibling = sib.next_sibling();
636
        }
637

            
638
153
        None
639
383
    }
640

            
641
1089006
    fn is_html_element_in_html_document(&self) -> bool {
642
1089006
        false
643
1089006
    }
644

            
645
6935229
    fn has_local_name(&self, local_name: &LocalName) -> bool {
646
6935229
        self.0.borrow_element().element_name().local == local_name.0
647
6935229
    }
648

            
649
    /// Empty string for no namespace
650
8798806
    fn has_namespace(&self, ns: &Namespace) -> bool {
651
8798806
        self.0.borrow_element().element_name().ns == *ns
652
8798806
    }
653

            
654
    /// Whether this element and the `other` element have the same local name and namespace.
655
344
    fn is_same_type(&self, other: &Self) -> bool {
656
344
        self.0.borrow_element().element_name() == other.0.borrow_element().element_name()
657
344
    }
658

            
659
8664
    fn attr_matches(
660
8664
        &self,
661
8664
        ns: &NamespaceConstraint<&Namespace>,
662
8664
        local_name: &LocalName,
663
8664
        operation: &AttrSelectorOperation<&AttributeValue>,
664
8664
    ) -> bool {
665
8664
        self.0
666
8664
            .borrow_element()
667
8664
            .get_attributes()
668
8664
            .iter()
669
26657
            .find(|(attr, _)| {
670
26657
                // do we have an attribute that matches the namespace and local_name?
671
26657
                match *ns {
672
                    NamespaceConstraint::Any => local_name.0 == attr.local,
673
26657
                    NamespaceConstraint::Specific(ns) => {
674
26657
                        QualName::new(None, ns.clone(), local_name.0.clone()) == *attr
675
                    }
676
                }
677
26657
            })
678
8664
            .map(|(_, value)| {
679
1311
                // we have one; does the attribute's value match the expected operation?
680
1311
                operation.eval_str(value)
681
8664
            })
682
8664
            .unwrap_or(false)
683
8664
    }
684

            
685
969
    fn match_non_ts_pseudo_class(
686
969
        &self,
687
969
        pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
688
969
        _context: &mut MatchingContext<'_, Self::Impl>,
689
969
    ) -> bool
690
969
where {
691
969
        match pc {
692
57
            NonTSPseudoClass::Link => self.is_link(),
693
            NonTSPseudoClass::Visited => false,
694
912
            NonTSPseudoClass::Lang(css_lang) => self
695
912
                .0
696
912
                .borrow_element()
697
912
                .get_computed_values()
698
912
                .xml_lang()
699
912
                .0
700
912
                .as_ref()
701
912
                .is_some_and(|e_lang| {
702
646
                    css_lang
703
646
                        .iter()
704
722
                        .any(|l| l.is_language_range() && l.matches(e_lang))
705
912
                }),
706
        }
707
969
    }
708

            
709
    fn match_pseudo_element(
710
        &self,
711
        _pe: &<Self::Impl as SelectorImpl>::PseudoElement,
712
        _context: &mut MatchingContext<'_, Self::Impl>,
713
    ) -> bool {
714
        // unsupported
715
        false
716
    }
717

            
718
    /// Whether this element is a `link`.
719
16644
    fn is_link(&self) -> bool {
720
16644
        // Style as link only if href is specified at all.
721
16644
        //
722
16644
        // The SVG and CSS specifications do not seem to clearly
723
16644
        // say what happens when you have an `<svg:a>` tag with no
724
16644
        // `(xlink:|svg:)href` attribute. However, both Firefox and Chromium
725
16644
        // consider a bare `<svg:a>` element with no href to be NOT
726
16644
        // a link, so to avoid nasty surprises, we do the same.
727
16644
        // Empty href's, however, ARE considered links.
728
16644
        self.0.is_element()
729
16644
            && match *self.0.borrow_element_data() {
730
57
                crate::element::ElementData::Link(ref link) => link.link.is_some(),
731
16587
                _ => false,
732
            }
733
16644
    }
734

            
735
    /// Returns whether the element is an HTML `<slot>` element.
736
    fn is_html_slot_element(&self) -> bool {
737
        false
738
    }
739

            
740
13606
    fn has_id(&self, id: &Identifier, case_sensitivity: CaseSensitivity) -> bool {
741
13606
        self.0
742
13606
            .borrow_element()
743
13606
            .get_id()
744
13606
            .map(|self_id| case_sensitivity.eq(self_id.as_bytes(), id.0.as_bytes()))
745
13606
            .unwrap_or(false)
746
13606
    }
747

            
748
17483
    fn has_class(&self, name: &Identifier, case_sensitivity: CaseSensitivity) -> bool {
749
17483
        self.0
750
17483
            .borrow_element()
751
17483
            .get_class()
752
17483
            .map(|classes| {
753
6253
                classes
754
6253
                    .split_whitespace()
755
8211
                    .any(|class| case_sensitivity.eq(class.as_bytes(), name.0.as_bytes()))
756
17483
            })
757
17483
            .unwrap_or(false)
758
17483
    }
759

            
760
    fn imported_part(&self, _name: &Identifier) -> Option<Identifier> {
761
        // unsupported
762
        None
763
    }
764

            
765
    fn is_part(&self, _name: &Identifier) -> bool {
766
        // unsupported
767
        false
768
    }
769

            
770
    /// Returns whether this element matches `:empty`.
771
    ///
772
    /// That is, whether it does not contain any child element or any non-zero-length text node.
773
    /// See <http://dev.w3.org/csswg/selectors-3/#empty-pseudo>.
774
40
    fn is_empty(&self) -> bool {
775
40
        // .all() returns true for the empty iterator
776
40
        self.0
777
40
            .children()
778
40
            .all(|child| child.is_chars() && child.borrow_chars().is_empty())
779
40
    }
780

            
781
    /// Returns whether this element matches `:root`,
782
    /// i.e. whether it is the root element of a document.
783
    ///
784
    /// Note: this can be false even if `.parent_element()` is `None`
785
    /// if the parent node is a `DocumentFragment`.
786
23400
    fn is_root(&self) -> bool {
787
23400
        self.0.parent().is_none()
788
23400
    }
789

            
790
    /// Returns the first child element of this element.
791
    fn first_element_child(&self) -> Option<Self> {
792
        self.0
793
            .children()
794
            .find(|child| child.is_element())
795
            .map(|n| n.into())
796
    }
797

            
798
    /// Applies the given selector flags to this element.
799
    fn apply_selector_flags(&self, _: ElementSelectorFlags) {
800
        todo!()
801
    }
802
}
803

            
804
/// Origin for a stylesheet, per CSS 2.2.
805
///
806
/// This is used when sorting selector matches according to their origin and specificity.
807
///
808
/// CSS2.2: <https://www.w3.org/TR/CSS22/cascade.html#cascading-order>
809
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
810
pub enum Origin {
811
    UserAgent,
812
    User,
813
    Author,
814
}
815

            
816
/// A parsed CSS stylesheet.
817
pub struct Stylesheet {
818
    origin: Origin,
819
    qualified_rules: Vec<QualifiedRule>,
820
}
821

            
822
/// A match during the selector matching process
823
///
824
/// This struct comes from [`Stylesheet::get_matches`], and represents
825
/// that a certain node matched a CSS rule which has a selector with a
826
/// certain `specificity`.  The stylesheet's `origin` is also given here.
827
///
828
/// This type implements [`Ord`] so a list of `Match` can be sorted.
829
/// That implementation does ordering based on origin and specificity
830
/// as per <https://www.w3.org/TR/CSS22/cascade.html#cascading-order>.
831
struct Match<'a> {
832
    specificity: u32,
833
    origin: Origin,
834
    declaration: &'a Declaration,
835
}
836

            
837
impl<'a> Ord for Match<'a> {
838
9063
    fn cmp(&self, other: &Self) -> Ordering {
839
9063
        match self.origin.cmp(&other.origin) {
840
8911
            Ordering::Equal => self.specificity.cmp(&other.specificity),
841
152
            o => o,
842
        }
843
9063
    }
844
}
845

            
846
impl<'a> PartialOrd for Match<'a> {
847
9063
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
848
9063
        Some(self.cmp(other))
849
9063
    }
850
}
851

            
852
impl<'a> PartialEq for Match<'a> {
853
    fn eq(&self, other: &Self) -> bool {
854
        self.origin == other.origin && self.specificity == other.specificity
855
    }
856
}
857

            
858
impl<'a> Eq for Match<'a> {}
859

            
860
impl Stylesheet {
861
2794
    fn empty(origin: Origin) -> Stylesheet {
862
2794
        Stylesheet {
863
2794
            origin,
864
2794
            qualified_rules: Vec::new(),
865
2794
        }
866
2794
    }
867

            
868
    /// Parses a new stylesheet from CSS data in a string.
869
    ///
870
    /// The `url_resolver_url` is required for `@import` rules, so that librsvg can determine if
871
    /// the requested path is allowed.
872
2775
    pub fn from_data(
873
2775
        buf: &str,
874
2775
        url_resolver: &UrlResolver,
875
2775
        origin: Origin,
876
2775
        session: Session,
877
2775
    ) -> Result<Self, LoadingError> {
878
2775
        let mut stylesheet = Stylesheet::empty(origin);
879
2775
        stylesheet.add_rules_from_string(buf, url_resolver, session)?;
880
2775
        Ok(stylesheet)
881
2775
    }
882

            
883
    /// Parses a new stylesheet by loading CSS data from a URL.
884
19
    pub fn from_href(
885
19
        aurl: &AllowedUrl,
886
19
        origin: Origin,
887
19
        session: Session,
888
19
    ) -> Result<Self, LoadingError> {
889
19
        let mut stylesheet = Stylesheet::empty(origin);
890
19
        stylesheet.load(aurl, session)?;
891
19
        Ok(stylesheet)
892
19
    }
893

            
894
    /// Parses the CSS rules in `buf` and appends them to the stylesheet.
895
    ///
896
    /// The `url_resolver_url` is required for `@import` rules, so that librsvg can determine if
897
    /// the requested path is allowed.
898
    ///
899
    /// If there is an `@import` rule, its rules will be recursively added into the
900
    /// stylesheet, in the order in which they appear.
901
2832
    fn add_rules_from_string(
902
2832
        &mut self,
903
2832
        buf: &str,
904
2832
        url_resolver: &UrlResolver,
905
2832
        session: Session,
906
2832
    ) -> Result<(), LoadingError> {
907
2832
        let mut input = ParserInput::new(buf);
908
2832
        let mut parser = Parser::new(&mut input);
909
2832
        let mut rule_parser = RuleParser {
910
2832
            session: session.clone(),
911
2832
        };
912
2832

            
913
2832
        StyleSheetParser::new(&mut parser, &mut rule_parser)
914
8819
            .filter_map(|r| match r {
915
8781
                Ok(rule) => Some(rule),
916
38
                Err(e) => {
917
38
                    rsvg_log!(session, "Invalid rule; ignoring: {:?}", e);
918
38
                    None
919
                }
920
8819
            })
921
8781
            .for_each(|rule| match rule {
922
38
                Rule::AtRule(AtRule::Import(url)) => match url_resolver.resolve_href(&url) {
923
38
                    Ok(aurl) => {
924
38
                        // ignore invalid imports
925
38
                        let _ = self.load(&aurl, session.clone());
926
38
                    }
927

            
928
                    Err(e) => {
929
                        rsvg_log!(session, "Not loading stylesheet from \"{}\": {}", url, e);
930
                    }
931
                },
932

            
933
8743
                Rule::QualifiedRule(qr) => self.qualified_rules.push(qr),
934
8781
            });
935
2832

            
936
2832
        Ok(())
937
2832
    }
938

            
939
    /// Parses a stylesheet referenced by an URL
940
57
    fn load(&mut self, aurl: &AllowedUrl, session: Session) -> Result<(), LoadingError> {
941
57
        io::acquire_data(aurl, None)
942
57
            .map_err(LoadingError::from)
943
57
            .and_then(|data| {
944
57
                let BinaryData {
945
57
                    data: bytes,
946
57
                    mime_type,
947
57
                } = data;
948
57

            
949
57
                if is_text_css(&mime_type) {
950
57
                    Ok(bytes)
951
                } else {
952
                    rsvg_log!(session, "\"{}\" is not of type text/css; ignoring", aurl);
953
                    Err(LoadingError::BadCss)
954
                }
955
57
            })
956
57
            .and_then(|bytes| {
957
57
                String::from_utf8(bytes).map_err(|_| {
958
                    rsvg_log!(
959
                        session,
960
                        "\"{}\" does not contain valid UTF-8 CSS data; ignoring",
961
                        aurl
962
                    );
963
                    LoadingError::BadCss
964
57
                })
965
57
            })
966
57
            .and_then(|utf8| {
967
57
                let url = (**aurl).clone();
968
57
                self.add_rules_from_string(&utf8, &UrlResolver::new(Some(url)), session)
969
57
            })
970
57
    }
971

            
972
    /// Appends the style declarations that match a specified node to a given vector
973
473411
    fn get_matches<'a>(
974
473411
        &'a self,
975
473411
        node: &Node,
976
473411
        match_ctx: &mut MatchingContext<'_, Selector>,
977
473411
        acc: &mut Vec<Match<'a>>,
978
473411
    ) {
979
1923607
        for rule in &self.qualified_rules {
980
10235492
            for selector in &rule.selectors.0 {
981
                // This magic call is stolen from selectors::matching::matches_selector_list()
982
8785296
                let matches = selectors::matching::matches_selector(
983
8785296
                    selector,
984
8785296
                    0,
985
8785296
                    None,
986
8785296
                    &RsvgElement(node.clone()),
987
8785296
                    match_ctx,
988
8785296
                );
989
8785296

            
990
8785296
                if matches {
991
67488
                    for decl in rule.declarations.iter() {
992
67488
                        acc.push(Match {
993
67488
                            declaration: decl,
994
67488
                            specificity: selector.specificity(),
995
67488
                            origin: self.origin,
996
67488
                        });
997
67488
                    }
998
8721722
                }
999
            }
        }
473411
    }
}
57
fn is_text_css(mime_type: &Mime) -> bool {
57
    mime_type.type_ == "text" && mime_type.subtype == "css"
57
}
/// Runs the CSS cascade on the specified tree from all the stylesheets
19562
pub fn cascade(
19562
    root: &mut Node,
19562
    ua_stylesheets: &[Stylesheet],
19562
    author_stylesheets: &[Stylesheet],
19562
    user_stylesheets: &[Stylesheet],
19562
    session: &Session,
19562
) {
1093376
    for mut node in root.descendants().filter(|n| n.is_element()) {
458363
        let mut matches = Vec::new();
458363

            
458363
        // xml:lang needs to be inherited before selector matching, so it
458363
        // can't be done in the usual SpecifiedValues::to_computed_values,
458363
        // which is called by cascade() and runs after matching.
458363
        let parent = node.parent().clone();
458363
        node.borrow_element_mut().inherit_xml_lang(parent);
458363

            
458363
        let mut cache = NthIndexCache::default();
458363
        let mut match_ctx = MatchingContext::new(
458363
            MatchingMode::Normal,
458363
            // FIXME: how the fuck does one set up a bloom filter here?
458363
            None,
458363
            &mut cache,
458363
            QuirksMode::NoQuirks,
458363
            NeedsSelectorFlags::No,
458363
            IgnoreNthChildForInvalidation::No,
458363
        );
473411
        for s in ua_stylesheets
458363
            .iter()
458363
            .chain(author_stylesheets)
458363
            .chain(user_stylesheets)
473411
        {
473411
            s.get_matches(&node, &mut match_ctx, &mut matches);
473411
        }
458363
        matches.as_mut_slice().sort();
458363

            
458363
        let mut element = node.borrow_element_mut();
525851
        for m in matches {
67488
            element.apply_style_declaration(m.declaration, m.origin);
67488
        }
458363
        element.set_style_attribute(session);
    }
19562
    let values = ComputedValues::default();
19562
    root.cascade(&values);
19562
}
#[cfg(test)]
mod tests {
    use super::*;
    use selectors::Element;
    use crate::document::Document;
    use crate::is_element_of_type;
    #[test]
1
    fn xml_lang() {
1
        let document = Document::load_from_bytes(
1
            br#"<?xml version="1.0" encoding="UTF-8"?>
1
<svg xmlns="http://www.w3.org/2000/svg" xml:lang="zh">
1
  <text id="a" x="10" y="10" width="30" height="30"></text>
1
  <text id="b" x="10" y="20" width="30" height="30" xml:lang="en"></text>
1
</svg>
1
"#,
1
        );
1
        let a = document.lookup_internal_node("a").unwrap();
1
        assert_eq!(
1
            a.borrow_element()
1
                .get_computed_values()
1
                .xml_lang()
1
                .0
1
                .unwrap()
1
                .as_str(),
1
            "zh"
1
        );
1
        let b = document.lookup_internal_node("b").unwrap();
1
        assert_eq!(
1
            b.borrow_element()
1
                .get_computed_values()
1
                .xml_lang()
1
                .0
1
                .unwrap()
1
                .as_str(),
1
            "en"
1
        );
1
    }
    #[test]
1
    fn impl_element() {
1
        let document = Document::load_from_bytes(
1
            br#"<?xml version="1.0" encoding="UTF-8"?>
1
<svg xmlns="http://www.w3.org/2000/svg" id="a">
1
  <rect id="b" x="10" y="10" width="30" height="30"/>
1
  <circle id="c" cx="10" cy="10" r="10"/>
1
  <rect id="d" class="foo bar"/>
1
</svg>
1
"#,
1
        );
1

            
1
        let a = document.lookup_internal_node("a").unwrap();
1
        let b = document.lookup_internal_node("b").unwrap();
1
        let c = document.lookup_internal_node("c").unwrap();
1
        let d = document.lookup_internal_node("d").unwrap();
1

            
1
        // Node types
1
        assert!(is_element_of_type!(a, Svg));
1
        assert!(is_element_of_type!(b, Rect));
1
        assert!(is_element_of_type!(c, Circle));
1
        assert!(is_element_of_type!(d, Rect));
1
        let a = RsvgElement(a);
1
        let b = RsvgElement(b);
1
        let c = RsvgElement(c);
1
        let d = RsvgElement(d);
1

            
1
        // Tree navigation
1

            
1
        assert_eq!(a.parent_element(), None);
1
        assert_eq!(b.parent_element(), Some(a.clone()));
1
        assert_eq!(c.parent_element(), Some(a.clone()));
1
        assert_eq!(d.parent_element(), Some(a.clone()));
1
        assert_eq!(b.next_sibling_element(), Some(c.clone()));
1
        assert_eq!(c.next_sibling_element(), Some(d.clone()));
1
        assert_eq!(d.next_sibling_element(), None);
1
        assert_eq!(b.prev_sibling_element(), None);
1
        assert_eq!(c.prev_sibling_element(), Some(b.clone()));
1
        assert_eq!(d.prev_sibling_element(), Some(c.clone()));
        // Other operations
1
        assert!(a.has_local_name(&LocalName::from("svg")));
1
        assert!(a.has_namespace(&ns!(svg)));
1
        assert!(!a.is_same_type(&b));
1
        assert!(b.is_same_type(&d));
1
        assert!(a.has_id(
1
            &Identifier::from("a"),
1
            CaseSensitivity::AsciiCaseInsensitive
1
        ));
1
        assert!(!b.has_id(
1
            &Identifier::from("foo"),
1
            CaseSensitivity::AsciiCaseInsensitive
1
        ));
1
        assert!(d.has_class(
1
            &Identifier::from("foo"),
1
            CaseSensitivity::AsciiCaseInsensitive
1
        ));
1
        assert!(d.has_class(
1
            &Identifier::from("bar"),
1
            CaseSensitivity::AsciiCaseInsensitive
1
        ));
1
        assert!(!a.has_class(
1
            &Identifier::from("foo"),
1
            CaseSensitivity::AsciiCaseInsensitive
1
        ));
1
        assert!(d.is_empty());
1
        assert!(!a.is_empty());
1
    }
}