[librsvg: 5/8] Use ComputedValues for xml:lang
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 5/8] Use ComputedValues for xml:lang
- Date: Fri, 15 Oct 2021 21:01:05 +0000 (UTC)
commit aecee4990fd53353a600711db66ae0a163364947
Author: Michael Howell <michael notriddle com>
Date: Thu Oct 14 18:06:00 2021 -0700
Use ComputedValues for xml:lang
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/606>
src/css.rs | 10 +++++++++-
src/document.rs | 16 +---------------
src/element.rs | 36 ++++--------------------------------
src/properties.rs | 16 +++++++++++++++-
src/property_defs.rs | 12 +++++++++---
src/text.rs | 2 +-
6 files changed, 39 insertions(+), 53 deletions(-)
---
diff --git a/src/css.rs b/src/css.rs
index 417c1219..6803b875 100644
--- a/src/css.rs
+++ b/src/css.rs
@@ -557,7 +557,10 @@ impl selectors::Element for RsvgElement {
NonTSPseudoClass::Lang(css_lang) => self
.0
.borrow_element()
- .get_language()
+ .get_computed_values()
+ .xml_lang()
+ .0
+ .as_ref()
.map_or(false, |e_lang| css_lang.iter().any(|l| l.matches(e_lang))),
}
}
@@ -838,6 +841,11 @@ pub fn cascade(
for mut node in root.descendants().filter(|n| n.is_element()) {
let mut matches = Vec::new();
+ // xml:lang needs to be inherited before selector matching, so it
+ // can't be done in the usual SpecifiedValues::to_computed_values,
+ // which is called by cascade() and runs after matching.
+ node.borrow_element_mut().inherit_xml_lang();
+
let mut match_ctx = MatchingContext::new(
MatchingMode::Normal,
// FIXME: how the fuck does one set up a bloom filter here?
diff --git a/src/document.rs b/src/document.rs
index 1db4e7c8..406a6d79 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -487,7 +487,7 @@ impl DocumentBuilder {
attrs: Attributes,
parent: Option<Node>,
) -> Node {
- let mut node = Node::new(NodeData::new_element(name, attrs));
+ let node = Node::new(NodeData::new_element(name, attrs));
if let Some(id) = node.borrow_element().get_id() {
// This is so we don't overwrite an existing id
@@ -498,20 +498,6 @@ impl DocumentBuilder {
if let Some(mut parent) = parent {
parent.append(node.clone());
-
- // If no language is specified on an element,
- // it implicitly gets one from the parent,
- // https://www.w3.org/International/questions/qa-when-xmllang#bytheway
- //
- // "It's important to remember that xml:lang has scope: lower-level elements inherit
- // the language attribute. This can be used to identify the language for a lot of
- // content (without having redundant language tags on every element)."
- if let Some(parent_language) = parent.borrow_element().get_language() {
- let mut child = node.borrow_element_mut();
- if child.get_language().is_none() {
- child.set_language(parent_language.clone());
- }
- }
} else if self.tree.is_none() {
self.tree = Some(node.clone());
} else {
diff --git a/src/element.rs b/src/element.rs
index 4eb8c1b4..5b19ecd8 100644
--- a/src/element.rs
+++ b/src/element.rs
@@ -1,12 +1,10 @@
//! SVG Elements.
-use language_tags::LanguageTag;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::ops::Deref;
-use std::str::FromStr;
use crate::accept_language::UserLanguage;
use crate::bbox::BoundingBox;
@@ -106,7 +104,6 @@ pub struct ElementInner<T: SetAttributes + Draw> {
required_extensions: Option<RequiredExtensions>,
required_features: Option<RequiredFeatures>,
system_language: Option<SystemLanguage>,
- language: Option<LanguageTag>,
pub element_impl: T,
}
@@ -131,13 +128,11 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
required_extensions: Default::default(),
required_features: Default::default(),
system_language: Default::default(),
- language: Default::default(),
element_impl,
};
let mut set_attributes = || -> Result<(), ElementError> {
e.set_conditional_processing_attributes()?;
- e.set_language_attribute()?;
e.set_presentation_attributes()?;
Ok(())
};
@@ -165,12 +160,8 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
self.class.as_deref()
}
- fn get_language(&self) -> Option<&LanguageTag> {
- self.language.as_ref()
- }
-
- fn set_language(&mut self, language_tag: LanguageTag) {
- self.language = Some(language_tag);
+ fn inherit_xml_lang(&mut self) {
+ self.specified_values.inherit_xml_lang(&mut self.values);
}
fn get_specified_values(&self) -> &SpecifiedValues {
@@ -202,21 +193,6 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
.unwrap_or(true)
}
- fn set_language_attribute(&mut self) -> Result<(), ElementError> {
- for (attr, value) in self.attributes.iter() {
- if attr.expanded() == expanded_name!(xml "lang") {
- self.language = Some(
- LanguageTag::from_str(value)
- .map_err(|e| {
- ValueErrorKind::parse_error(&format!("invalid language tag: \"{}\"", e))
- })
- .attribute(attr)?,
- );
- }
- }
- Ok(())
- }
-
fn set_conditional_processing_attributes(&mut self) -> Result<(), ElementError> {
for (attr, value) in self.attributes.iter() {
match attr.expanded() {
@@ -525,12 +501,8 @@ impl Element {
call_inner!(self, get_class)
}
- pub fn get_language(&self) -> Option<&LanguageTag> {
- call_inner!(self, get_language)
- }
-
- pub fn set_language(&mut self, language: LanguageTag) {
- call_inner!(self, set_language, language)
+ pub fn inherit_xml_lang(&mut self) {
+ call_inner!(self, inherit_xml_lang)
}
pub fn get_specified_values(&self) -> &SpecifiedValues {
diff --git a/src/properties.rs b/src/properties.rs
index d2ea9f85..d661fb0e 100644
--- a/src/properties.rs
+++ b/src/properties.rs
@@ -728,7 +728,6 @@ impl SpecifiedValues {
compute!(UnicodeBidi, unicode_bidi);
compute!(Visibility, visibility);
compute!(WritingMode, writing_mode);
- compute!(XmlLang, xml_lang);
compute!(XmlSpace, xml_space);
computed.transform = self.transform.unwrap_or_else(|| {
@@ -741,6 +740,21 @@ impl SpecifiedValues {
});
}
+ /// This is a somewhat egregious hack to allow xml:lang to be stored as a presentational
+ /// attribute. Presentational attributes can often be influenced by stylesheets,
+ /// so they're cascaded after selector matching is done, but xml:lang can be queried by
+ /// CSS selectors, so they need to be cascaded *first*.
+ pub fn inherit_xml_lang(&self, computed: &mut ComputedValues) {
+ let prop_val = self.get_property(PropertyId::XmlLang);
+ if let ParsedProperty::XmlLang(s) = prop_val {
+ computed.set_value(ComputedValue::XmlLang(
+ s.compute(&computed.xml_lang(), computed),
+ ));
+ } else {
+ unreachable!();
+ }
+ }
+
pub fn is_overflow(&self) -> bool {
if let Some(overflow_index) = self.property_index(PropertyId::Overflow) {
match self.props[overflow_index] {
diff --git a/src/property_defs.rs b/src/property_defs.rs
index 6eb8c713..4923667e 100644
--- a/src/property_defs.rs
+++ b/src/property_defs.rs
@@ -35,8 +35,10 @@
//!
//! * An implementation of the [`Parse`] trait for the underlying type.
use std::convert::TryInto;
+use std::str::FromStr;
use cssparser::{Parser, Token};
+use language_tags::LanguageTag;
use crate::dasharray::Dasharray;
use crate::error::*;
@@ -1088,13 +1090,17 @@ make_property!(
XmlLang,
default: None,
inherits_automatically: true,
- newtype: Option<String>,
+ newtype: Option<LanguageTag>,
parse_impl: {
impl Parse for XmlLang {
fn parse<'i>(
parser: &mut Parser<'i, '_>,
) -> Result<XmlLang, ParseError<'i>> {
- Ok(XmlLang(Some(parser.expect_ident()?.to_string())))
+ let language_tag = parser.expect_ident()?;
+ let language_tag = LanguageTag::from_str(language_tag).map_err(|_| {
+ parser.new_custom_error(ValueErrorKind::parse_error("invalid syntax for 'xml:lang'
parameter"))
+ })?;
+ Ok(XmlLang(Some(language_tag)))
}
}
},
@@ -1105,7 +1111,7 @@ make_property!(
fn parses_xml_lang() {
assert_eq!(
XmlLang::parse_str("es-MX").unwrap(),
- XmlLang(Some("es-MX".to_string()))
+ XmlLang(Some(LanguageTag::from_str("es-MX").unwrap()))
);
assert!(XmlLang::parse_str("").is_err());
diff --git a/src/text.rs b/src/text.rs
index f5d715f9..7f185972 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -869,7 +869,7 @@ fn create_pango_layout(draw_ctx: &DrawingCtx, props: &FontProperties, text: &str
let pango_context = draw_ctx.create_pango_context();
if let XmlLang(Some(ref lang)) = props.xml_lang {
- pango_context.set_language(&pango::Language::from_string(lang));
+ pango_context.set_language(&pango::Language::from_string(lang.as_str()));
}
pango_context.set_base_gravity(pango::Gravity::from(props.writing_mode));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]