From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../style/properties/shorthands/background.mako.rs | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 servo/components/style/properties/shorthands/background.mako.rs (limited to 'servo/components/style/properties/shorthands/background.mako.rs') diff --git a/servo/components/style/properties/shorthands/background.mako.rs b/servo/components/style/properties/shorthands/background.mako.rs new file mode 100644 index 0000000000..08838233f6 --- /dev/null +++ b/servo/components/style/properties/shorthands/background.mako.rs @@ -0,0 +1,289 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +// TODO: other background-* properties +<%helpers:shorthand name="background" + engines="gecko servo-2013 servo-2020" + sub_properties="background-color background-position-x background-position-y background-repeat + background-attachment background-image background-size background-origin + background-clip" + spec="https://drafts.csswg.org/css-backgrounds/#the-background"> + use crate::properties::longhands::{background_position_x, background_position_y, background_repeat}; + use crate::properties::longhands::{background_attachment, background_color, background_image, background_size, background_origin}; + use crate::properties::longhands::background_clip; + use crate::properties::longhands::background_clip::single_value::computed_value::T as Clip; + use crate::properties::longhands::background_origin::single_value::computed_value::T as Origin; + use crate::values::specified::{AllowQuirks, Color, Position, PositionComponent}; + use crate::parser::Parse; + + // FIXME(emilio): Should be the same type! + impl From for background_clip::single_value::SpecifiedValue { + fn from(origin: background_origin::single_value::SpecifiedValue) -> + background_clip::single_value::SpecifiedValue { + match origin { + background_origin::single_value::SpecifiedValue::ContentBox => + background_clip::single_value::SpecifiedValue::ContentBox, + background_origin::single_value::SpecifiedValue::PaddingBox => + background_clip::single_value::SpecifiedValue::PaddingBox, + background_origin::single_value::SpecifiedValue::BorderBox => + background_clip::single_value::SpecifiedValue::BorderBox, + } + } + } + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut background_color = None; + + % for name in "image position_x position_y repeat size attachment origin clip".split(): + // Vec grows from 0 to 4 by default on first push(). So allocate with + // capacity 1, so in the common case of only one item we don't way + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut background_${name} = Vec::with_capacity(1); + % endfor + input.parse_comma_separated(|input| { + // background-color can only be in the last element, so if it + // is parsed anywhere before, the value is invalid. + if background_color.is_some() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + % for name in "image position repeat size attachment origin clip".split(): + let mut ${name} = None; + % endfor + loop { + if background_color.is_none() { + if let Ok(value) = input.try_parse(|i| Color::parse(context, i)) { + background_color = Some(value); + continue + } + } + if position.is_none() { + if let Ok(value) = input.try_parse(|input| { + Position::parse_three_value_quirky(context, input, AllowQuirks::No) + }) { + position = Some(value); + + // Parse background size, if applicable. + size = input.try_parse(|input| { + input.expect_delim('/')?; + background_size::single_value::parse(context, input) + }).ok(); + + continue + } + } + % for name in "image repeat attachment origin clip".split(): + if ${name}.is_none() { + if let Ok(value) = input.try_parse(|input| background_${name}::single_value + ::parse(context, input)) { + ${name} = Some(value); + continue + } + } + % endfor + break + } + if clip.is_none() { + if let Some(origin) = origin { + clip = Some(background_clip::single_value::SpecifiedValue::from(origin)); + } + } + let mut any = false; + % for name in "image position repeat size attachment origin clip".split(): + any = any || ${name}.is_some(); + % endfor + any = any || background_color.is_some(); + if any { + if let Some(position) = position { + background_position_x.push(position.horizontal); + background_position_y.push(position.vertical); + } else { + background_position_x.push(PositionComponent::zero()); + background_position_y.push(PositionComponent::zero()); + } + % for name in "image repeat size attachment origin clip".split(): + if let Some(bg_${name}) = ${name} { + background_${name}.push(bg_${name}); + } else { + background_${name}.push(background_${name}::single_value + ::get_initial_specified_value()); + } + % endfor + Ok(()) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + })?; + + Ok(expanded! { + background_color: background_color.unwrap_or(Color::transparent()), + % for name in "image position_x position_y repeat size attachment origin clip".split(): + background_${name}: background_${name}::SpecifiedValue(background_${name}.into()), + % endfor + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + let len = self.background_image.0.len(); + // There should be at least one declared value + if len == 0 { + return Ok(()); + } + + // If a value list length is differs then we don't do a shorthand serialization. + // The exceptions to this is color which appears once only and is serialized + // with the last item. + % for name in "image position_x position_y size repeat origin clip attachment".split(): + if len != self.background_${name}.0.len() { + return Ok(()); + } + % endfor + + for i in 0..len { + % for name in "image position_x position_y repeat size attachment origin clip".split(): + let ${name} = &self.background_${name}.0[i]; + % endfor + + if i != 0 { + dest.write_str(", ")?; + } + + let mut wrote_value = false; + + if i == len - 1 { + if *self.background_color != background_color::get_initial_specified_value() { + self.background_color.to_css(dest)?; + wrote_value = true; + } + } + + if *image != background_image::single_value::get_initial_specified_value() { + if wrote_value { + dest.write_char(' ')?; + } + image.to_css(dest)?; + wrote_value = true; + } + + // Size is only valid after a position so when there is a + // non-initial size we must also serialize position + if *position_x != PositionComponent::zero() || + *position_y != PositionComponent::zero() || + *size != background_size::single_value::get_initial_specified_value() + { + if wrote_value { + dest.write_char(' ')?; + } + + Position { + horizontal: position_x.clone(), + vertical: position_y.clone() + }.to_css(dest)?; + + wrote_value = true; + + if *size != background_size::single_value::get_initial_specified_value() { + dest.write_str(" / ")?; + size.to_css(dest)?; + } + } + + % for name in "repeat attachment".split(): + if *${name} != background_${name}::single_value::get_initial_specified_value() { + if wrote_value { + dest.write_char(' ')?; + } + ${name}.to_css(dest)?; + wrote_value = true; + } + % endfor + + if *origin != Origin::PaddingBox || *clip != Clip::BorderBox { + if wrote_value { + dest.write_char(' ')?; + } + origin.to_css(dest)?; + if *clip != From::from(*origin) { + dest.write_char(' ')?; + clip.to_css(dest)?; + } + + wrote_value = true; + } + + if !wrote_value { + image.to_css(dest)?; + } + } + + Ok(()) + } + } + + +<%helpers:shorthand name="background-position" + engines="gecko servo-2013 servo-2020" + flags="SHORTHAND_IN_GETCS" + sub_properties="background-position-x background-position-y" + spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position"> + use crate::properties::longhands::{background_position_x, background_position_y}; + use crate::values::specified::AllowQuirks; + use crate::values::specified::position::Position; + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + // Vec grows from 0 to 4 by default on first push(). So allocate with + // capacity 1, so in the common case of only one item we don't way + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut position_x = Vec::with_capacity(1); + let mut position_y = Vec::with_capacity(1); + let mut any = false; + + input.parse_comma_separated(|input| { + let value = Position::parse_three_value_quirky(context, input, AllowQuirks::Yes)?; + position_x.push(value.horizontal); + position_y.push(value.vertical); + any = true; + Ok(()) + })?; + if !any { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + Ok(expanded! { + background_position_x: background_position_x::SpecifiedValue(position_x.into()), + background_position_y: background_position_y::SpecifiedValue(position_y.into()), + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + let len = self.background_position_x.0.len(); + if len == 0 || len != self.background_position_y.0.len() { + return Ok(()); + } + for i in 0..len { + Position { + horizontal: self.background_position_x.0[i].clone(), + vertical: self.background_position_y.0[i].clone() + }.to_css(dest)?; + + if i < len - 1 { + dest.write_str(", ")?; + } + } + Ok(()) + } + } + -- cgit v1.2.3