diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 0666338058e..12a4c884336 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -51,7 +51,7 @@ use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS; use gecko_bindings::sugar::ownership::HasArcFFI; use parking_lot::RwLock; use properties::{ComputedValues, parse_style_attribute}; -use properties::PropertyDeclarationBlock; +use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; use properties::animated_properties::AnimationValueMap; use rule_tree::CascadeLevel as ServoCascadeLevel; use selector_parser::{ElementExt, Snapshot}; @@ -624,6 +624,24 @@ impl<'le> PresentationalHintsSynthetizer for GeckoElement<'le> { fn synthesize_presentational_hints_for_legacy_attributes(&self, hints: &mut V) where V: Push, { + use properties::longhands::text_align::SpecifiedValue; + lazy_static! { + static ref TH_RULE: ApplicableDeclarationBlock = { + let global_style_data = &*GLOBAL_STYLE_DATA; + let pdb = PropertyDeclarationBlock::with_one( + PropertyDeclaration::TextAlign(SpecifiedValue::MozCenterOrInherit), + Importance::Normal + ); + let arc = Arc::new(global_style_data.shared_lock.wrap(pdb)); + ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints) + }; + }; + + // elements get a default MozCenterOrInherit which may get overridden + if self.get_namespace() == &*Namespace(atom!("http://www.w3.org/1999/xhtml")) && + self.get_local_name().as_ptr() == atom!("th").as_ptr() { + hints.push(TH_RULE.clone()); + } let declarations = unsafe { Gecko_GetHTMLPresentationAttrDeclarationBlock(self.0) }; let declarations = declarations.and_then(|s| s.as_arc_opt()); if let Some(decl) = declarations { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 78db1f0bd62..bc6d5471b0d 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2797,8 +2797,12 @@ fn static_assert() { -webkit-text-stroke-width text-emphasis-position -moz-tab-size -moz-text-size-adjust"> <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " + - "-moz-right match-parent char") %> + "-moz-right char") %> + <% text_align_reachable_keyword = Keyword("text-align", "start end left right center justify char") %> ${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)} + // Stable rust errors on unreachable patterns, and there is overlap, so we run with the overlapping + // constants removed + ${impl_keyword_clone('text_align', 'mTextAlign', text_align_reachable_keyword)} pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) { self.gecko.mTextShadow.replace_with_new(v.0.len() as u32); diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index b24cdbbcacf..37d58b07386 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -250,11 +250,10 @@ ${helpers.single_keyword("text-align-last", spec="https://drafts.csswg.org/css-text/#propdef-text-align-last")} // TODO make this a shorthand and implement text-align-last/text-align-all -<%helpers:longhand name="text-align" animatable="False" spec="https://drafts.csswg.org/css-text/#propdef-text-align"> - pub use self::computed_value::T as SpecifiedValue; +<%helpers:longhand name="text-align" animatable="False" need_clone="True" + spec="https://drafts.csswg.org/css-text/#propdef-text-align"> use values::computed::ComputedValueAsSpecified; use values::HasViewportPercentage; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); pub mod computed_value { use style_traits::ToCss; @@ -299,21 +298,110 @@ ${helpers.single_keyword("text-align-last", _moz_center("-moz-center") => 6, _moz_left("-moz-left") => 7, _moz_right("-moz-right") => 8, - match_parent("match-parent") => 9, char("char") => 10, % endif } + + ${helpers.gecko_keyword_conversion(Keyword('text-align', + """left right center justify -moz-left -moz-right + -moz-center char end""", + gecko_strip_moz_prefix=False), type="T")} } + #[inline] pub fn get_initial_value() -> computed_value::T { computed_value::T::start } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - computed_value::T::parse(input) - } - ${helpers.gecko_keyword_conversion(Keyword('text-align', - """left right center justify -moz-left -moz-right - -moz-center char end match-parent""", - gecko_strip_moz_prefix=False))} + + + % if product == "gecko": + use std::fmt; + use style_traits::ToCss; + + #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] + pub enum SpecifiedValue { + Keyword(computed_value::T), + MatchParent, + MozCenterOrInherit, + } + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + // MozCenterOrInherit cannot be parsed, only set directly on th elements + if let Ok(key) = input.try(computed_value::T::parse) { + Ok(SpecifiedValue::Keyword(key)) + } else { + input.expect_ident_matching("match-parent")?; + Ok(SpecifiedValue::MatchParent) + } + } + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Keyword(key) => key.to_css(dest), + SpecifiedValue::MatchParent => dest.write_str("match-parent"), + SpecifiedValue::MozCenterOrInherit => Ok(()), + } + } + } + + impl SpecifiedValue { + pub fn from_gecko_keyword(kw: u32) -> Self { + use gecko_bindings::structs::NS_STYLE_TEXT_ALIGN_MATCH_PARENT; + if kw == NS_STYLE_TEXT_ALIGN_MATCH_PARENT { + SpecifiedValue::MatchParent + } else { + SpecifiedValue::Keyword(computed_value::T::from_gecko_keyword(kw)) + } + } + } + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Context) -> computed_value::T { + match *self { + SpecifiedValue::Keyword(key) => key, + SpecifiedValue::MatchParent => { + // on the root element we should still respect the dir + // but the parent dir of that element is LTR even if it's + // and will only be RTL if certain prefs have been set. + // In that case, the default behavior here will set it to left, + // but we want to set it to right -- instead set it to the default (`start`), + // which will do the right thing in this case (but not the general case) + if context.is_root_element { + return get_initial_value(); + } + let parent = context.inherited_style().get_inheritedtext().clone_text_align(); + let ltr = context.inherited_style().writing_mode.is_bidi_ltr(); + match (parent, ltr) { + (computed_value::T::start, true) => computed_value::T::left, + (computed_value::T::start, false) => computed_value::T::right, + (computed_value::T::end, true) => computed_value::T::right, + (computed_value::T::end, false) => computed_value::T::left, + _ => parent + } + } + SpecifiedValue::MozCenterOrInherit => { + let parent = context.inherited_style().get_inheritedtext().clone_text_align(); + if parent == computed_value::T::start { + computed_value::T::center + } else { + parent + } + } + } + } + + #[inline] + fn from_computed_value(computed: &computed_value::T) -> Self { + SpecifiedValue::Keyword(*computed) + } + } + % else: + impl ComputedValueAsSpecified for SpecifiedValue {} + pub use self::computed_value::T as SpecifiedValue; + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + computed_value::T::parse(input) + } + % endif // FIXME: This prop should be animatable.