[librsvg: 2/4] Implement `:link` pseudo-class
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/4] Implement `:link` pseudo-class
- Date: Tue, 12 Oct 2021 23:34:10 +0000 (UTC)
commit 8c0791ef49bf0d76139dbd98bfa531fb76335a3e
Author: Michael Howell <michael notriddle com>
Date: Fri Oct 8 17:22:45 2021 -0700
Implement `:link` pseudo-class
This also adds parsing for the `:visited` pseudo class,
but since librsvg maintains no history, it's not much of an implementation.
This change is included to make the test case in #738 pass,
which doesn't just try to match an `a` selector, but a whole
`a:link` selector.
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/601>
src/css.rs | 48 +++++++++++++++++----
src/structure.rs | 1 -
tests/fixtures/reftests/a-pseudo-class-ref.png | Bin 0 -> 3152 bytes
tests/fixtures/reftests/a-pseudo-class.svg | 30 +++++++++++++
.../a-inside-text-content-pseudo-class-738-ref.png | Bin 0 -> 2493 bytes
.../a-inside-text-content-pseudo-class-738.svg | 26 +++++++++++
6 files changed, 96 insertions(+), 9 deletions(-)
---
diff --git a/src/css.rs b/src/css.rs
index 3b19e795..1508060b 100644
--- a/src/css.rs
+++ b/src/css.rs
@@ -202,6 +202,19 @@ impl<'i> selectors::Parser<'i> for RuleParser {
// Or are CSS namespaces completely different, declared elsewhere?
None
}
+ fn parse_non_ts_pseudo_class(
+ &self,
+ location: SourceLocation,
+ name: CowRcStr<'i>,
+ ) -> Result<NonTSPseudoClass, cssparser::ParseError<'i, Self::Error>> {
+ match &*name {
+ "link" => Ok(NonTSPseudoClass::Link),
+ "visited" => Ok(NonTSPseudoClass::Visited),
+ _ => Err(location.new_custom_error(
+ selectors::parser::SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
+ )),
+ }
+ }
}
// `cssparser::RuleListParser` is a struct which requires that we
@@ -300,14 +313,20 @@ impl<'i> AtRuleParser<'i> for RuleParser {
/// Dummy type required by the SelectorImpl trait.
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct NonTSPseudoClass;
+pub enum NonTSPseudoClass {
+ Link,
+ Visited,
+}
impl ToCss for NonTSPseudoClass {
- fn to_css<W>(&self, _dest: &mut W) -> fmt::Result
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
- Ok(())
+ match self {
+ NonTSPseudoClass::Link => write!(dest, "link"),
+ NonTSPseudoClass::Visited => write!(dest, "visited"),
+ }
}
}
@@ -491,15 +510,17 @@ impl selectors::Element for RsvgElement {
fn match_non_ts_pseudo_class<F>(
&self,
- _pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
+ pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
_context: &mut MatchingContext<'_, Self::Impl>,
_flags_setter: &mut F,
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags),
{
- // unsupported
- false
+ match *pc {
+ NonTSPseudoClass::Link => self.is_link(),
+ NonTSPseudoClass::Visited => false,
+ }
}
fn match_pseudo_element(
@@ -513,8 +534,19 @@ impl selectors::Element for RsvgElement {
/// Whether this element is a `link`.
fn is_link(&self) -> bool {
- // FIXME: is this correct for SVG <a>, not HTML <a>?
- self.0.is_element() && is_element_of_type!(self.0, Link)
+ // Style as link only if href is specified at all.
+ //
+ // The SVG and CSS specifications do not seem to clearly
+ // say what happens when you have an `<svg:a>` tag with no
+ // `(xlink:|svg:)href` attribute. However, both Firefox and Chromium
+ // consider a bare `<svg:a>` element with no href to be NOT
+ // a link, so to avoid nasty surprises, we do the same.
+ // Empty href's, however, ARE considered links.
+ self.0.is_element()
+ && match &*self.0.borrow_element() {
+ crate::element::Element::Link(link) => link.link.is_some(),
+ _ => false,
+ }
}
/// Returns whether the element is an HTML <slot> element.
diff --git a/src/structure.rs b/src/structure.rs
index 8d47197d..28fde6d1 100644
--- a/src/structure.rs
+++ b/src/structure.rs
@@ -541,7 +541,6 @@ impl Draw for Link {
draw_ctx: &mut DrawingCtx,
clipping: bool,
) -> Result<BoundingBox, RenderingError> {
-
// If this element is inside of <text>, do not draw it.
// The <text> takes care of it.
for an in node.ancestors() {
diff --git a/tests/fixtures/reftests/a-pseudo-class-ref.png b/tests/fixtures/reftests/a-pseudo-class-ref.png
new file mode 100644
index 00000000..f61ff300
Binary files /dev/null and b/tests/fixtures/reftests/a-pseudo-class-ref.png differ
diff --git a/tests/fixtures/reftests/a-pseudo-class.svg b/tests/fixtures/reftests/a-pseudo-class.svg
new file mode 100644
index 00000000..699160d8
--- /dev/null
+++ b/tests/fixtures/reftests/a-pseudo-class.svg
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.1"
+ viewBox="0 0 500 600"
+ font-family="sans-serif"
+ font-size="18">
+ <defs>
+ <style>
+ a { fill: red; font-family: Helvetica; font-size:10; }
+ a:link { fill: black; }
+
+ text { fill: inherit; font-family: Helvetica; font-size:10; }
+ </style>
+ </defs>
+
+ <text x="250" y="25" class="head" text-anchor="middle">SVG CSS Tests</text>
+ <g transform="translate(0,50)"><a xlink:href="#foo">
+ <text x="50">a:link</text>
+ <text x="250" class="test">xlink:href</text>
+ </a></g>
+ <g transform="translate(0,150)"><a>
+ <text x="50">a:link</text>
+ <text x="250" class="test">no href, not link</text>
+ </a></g>
+
+</svg>
diff --git a/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738-ref.png
b/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738-ref.png
new file mode 100644
index 00000000..ea52230c
Binary files /dev/null and b/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738-ref.png
differ
diff --git a/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738.svg
b/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738.svg
new file mode 100644
index 00000000..bc2203b2
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/a-inside-text-content-pseudo-class-738.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.1"
+ viewBox="0 0 500 600"
+ font-family="sans-serif"
+ font-size="18">
+ <defs>
+ <style>
+ a { fill: white; font-family: Helvetica; font-size:10; }
+ a:link { fill: black; }
+
+ text { fill: black; font-family: Helvetica; font-size:10; }
+ </style>
+ </defs>
+
+ <text x="250" y="25" class="head" text-anchor="middle">SVG CSS Tests</text>
+ <g transform="translate(0,50)">
+ <text x="50">a:link</text>
+ <text x="250" class="test"><a xlink:href="#foo">xlink:href</a></text>
+ </g>
+
+</svg>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]