diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 4fe90fb560b..d95eed44dd9 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -495,6 +495,7 @@ class Longhand(Property): "Percentage", "PositiveIntegerOrNone", "Resize", + "RubyPosition", "SVGOpacity", "SVGPaintOrder", "ScrollSnapAlign", diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index 0ce27e0e18f..b8b603e8b2e 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -329,13 +329,13 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-ruby/#ruby-align-property", )} -${helpers.single_keyword( +${helpers.predefined_type( "ruby-position", - "over under", + "RubyPosition", + "Default::default()", engines="gecko", - animation_value_type="discrete", spec="https://drafts.csswg.org/css-ruby/#ruby-position-property", - gecko_enum_prefix="StyleRubyPosition", + animation_value_type="discrete", )} // CSS Writing Modes Module Level 3 diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 0c9496c2fad..5ed404cf5e3 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -87,7 +87,7 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::text::TextUnderlinePosition; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; -pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; +pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextDecorationLength, TextDecorationSkipInk}; pub use self::time::Time; diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index b77695e06c0..4f952fa21cc 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -19,7 +19,7 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; pub use crate::values::specified::text::{TextAlignLast, TextUnderlinePosition}; -pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak}; +pub use crate::values::specified::{LineBreak, OverflowWrap, RubyPosition, WordBreak}; pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition}; pub use crate::values::specified::{TextDecorationSkipInk, TextTransform}; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index d91f9b8195f..946bf3c2cc9 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -86,6 +86,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg_path::SVGPathData; pub use self::text::TextAlignLast; pub use self::text::TextUnderlinePosition; +pub use self::text::RubyPosition; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 7c5c712eb3e..3fe3b92c354 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -22,6 +22,7 @@ use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use style_traits::values::SequenceWriter; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{KeywordsCollectFn, SpecifiedValueInfo}; use unicode_segmentation::UnicodeSegmentation; /// A specified type for the `initial-letter` property. @@ -1193,3 +1194,85 @@ impl ToCss for TextUnderlinePosition { Ok(()) } } + +/// Values for `ruby-position` property +#[repr(u8)] +#[derive( + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + PartialEq, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[allow(missing_docs)] +pub enum RubyPosition { + AlternateOver, + AlternateUnder, + Over, + Under, +} + +impl Default for RubyPosition { + fn default() -> Self { + if static_prefs::pref!("layout.css.ruby.position-alternate.enabled") { + RubyPosition::AlternateOver + } else { + RubyPosition::Over + } + } +} + +impl Parse for RubyPosition { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + // Parse alternate before + let alternate_enabled = static_prefs::pref!("layout.css.ruby.position-alternate.enabled"); + let alternate = alternate_enabled && + input.try_parse(|i| i.expect_ident_matching("alternate")).is_ok(); + if alternate && input.is_exhausted() { + return Ok(RubyPosition::AlternateOver); + } + // Parse over / under + let over = try_match_ident_ignore_ascii_case! { input, + "over" => true, + "under" => false, + }; + // Parse alternate after + let alternate = alternate || + (alternate_enabled && + input.try_parse(|i| i.expect_ident_matching("alternate")).is_ok()); + + Ok(match (over, alternate) { + (true, true) => RubyPosition::AlternateOver, + (false, true) => RubyPosition::AlternateUnder, + (true, false) => RubyPosition::Over, + (false, false) => RubyPosition::Under, + }) + } +} + +impl ToCss for RubyPosition { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + dest.write_str(match self { + RubyPosition::AlternateOver => "alternate", + RubyPosition::AlternateUnder => "alternate under", + RubyPosition::Over => "over", + RubyPosition::Under => "under", + }) + } +} + +impl SpecifiedValueInfo for RubyPosition { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&["alternate", "over", "under"]) + } +}