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/border.mako.rs | 491 +++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 servo/components/style/properties/shorthands/border.mako.rs (limited to 'servo/components/style/properties/shorthands/border.mako.rs') diff --git a/servo/components/style/properties/shorthands/border.mako.rs b/servo/components/style/properties/shorthands/border.mako.rs new file mode 100644 index 0000000000..c6a87f3197 --- /dev/null +++ b/servo/components/style/properties/shorthands/border.mako.rs @@ -0,0 +1,491 @@ +/* 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" /> +<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %> + +${helpers.four_sides_shorthand( + "border-color", + "border-%s-color", + "specified::Color::parse", + engines="gecko servo-2013 servo-2020", + spec="https://drafts.csswg.org/css-backgrounds/#border-color", + allow_quirks="Yes", +)} + +${helpers.four_sides_shorthand( + "border-style", + "border-%s-style", + engines="gecko servo-2013 servo-2020", + spec="https://drafts.csswg.org/css-backgrounds/#border-style", +)} + +<%helpers:shorthand + name="border-width" + engines="gecko servo-2013 servo-2020" + sub_properties="${ + ' '.join('border-%s-width' % side + for side in PHYSICAL_SIDES)}" + spec="https://drafts.csswg.org/css-backgrounds/#border-width"> + use crate::values::generics::rect::Rect; + use crate::values::specified::{AllowQuirks, BorderSideWidth}; + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let rect = Rect::parse_with(context, input, |_, i| { + BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes) + })?; + Ok(expanded! { + border_top_width: rect.0, + border_right_width: rect.1, + border_bottom_width: rect.2, + border_left_width: rect.3, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + % for side in PHYSICAL_SIDES: + let ${side} = &self.border_${side}_width; + % endfor + Rect::new(top, right, bottom, left).to_css(dest) + } + } + + + +pub fn parse_border<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, +) -> Result<(specified::Color, specified::BorderStyle, specified::BorderSideWidth), ParseError<'i>> { + use crate::values::specified::{Color, BorderStyle, BorderSideWidth}; + let _unused = context; + let mut color = None; + let mut style = None; + let mut width = None; + let mut any = false; + loop { + if width.is_none() { + if let Ok(value) = input.try_parse(|i| BorderSideWidth::parse(context, i)) { + width = Some(value); + any = true; + } + } + if style.is_none() { + if let Ok(value) = input.try_parse(BorderStyle::parse) { + style = Some(value); + any = true; + continue + } + } + if color.is_none() { + if let Ok(value) = input.try_parse(|i| Color::parse(context, i)) { + color = Some(value); + any = true; + continue + } + } + break + } + if !any { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + Ok((color.unwrap_or(Color::CurrentColor), style.unwrap_or(BorderStyle::None), width.unwrap_or(BorderSideWidth::medium()))) +} + +% for side, logical in ALL_SIDES: + <% + spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side + if logical: + spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side + %> + <%helpers:shorthand + name="border-${side}" + engines="gecko servo-2013 servo-2020" + sub_properties="${' '.join( + 'border-%s-%s' % (side, prop) + for prop in ['width', 'style', 'color'] + )}" + aliases="${maybe_moz_logical_alias(engine, (side, logical), '-moz-border-%s')}" + spec="${spec}"> + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let (color, style, width) = super::parse_border(context, input)?; + Ok(expanded! { + border_${to_rust_ident(side)}_color: color, + border_${to_rust_ident(side)}_style: style, + border_${to_rust_ident(side)}_width: width + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + crate::values::specified::border::serialize_directional_border( + dest, + self.border_${to_rust_ident(side)}_width, + self.border_${to_rust_ident(side)}_style, + self.border_${to_rust_ident(side)}_color + ) + } + } + + +% endfor + +<%helpers:shorthand name="border" + engines="gecko servo-2013 servo-2020" + sub_properties="${' '.join('border-%s-%s' % (side, prop) + for side in PHYSICAL_SIDES for prop in ['width', 'style', 'color'] + )} + ${' '.join('border-image-%s' % name + for name in ['outset', 'repeat', 'slice', 'source', 'width'])}" + derive_value_info="False" + spec="https://drafts.csswg.org/css-backgrounds/#border"> + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + use crate::properties::longhands::{border_image_outset, border_image_repeat, border_image_slice}; + use crate::properties::longhands::{border_image_source, border_image_width}; + + let (color, style, width) = super::parse_border(context, input)?; + Ok(expanded! { + % for side in PHYSICAL_SIDES: + border_${side}_color: color.clone(), + border_${side}_style: style, + border_${side}_width: width.clone(), + % endfor + + // The ‘border’ shorthand resets ‘border-image’ to its initial value. + // See https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands + % for name in "outset repeat slice source width".split(): + border_image_${name}: border_image_${name}::get_initial_specified_value(), + % endfor + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + use crate::properties::longhands; + + // If any of the border-image longhands differ from their initial specified values we should not + // invoke serialize_directional_border(), so there is no point in continuing on to compute all_equal. + % for name in "outset repeat slice source width".split(): + if *self.border_image_${name} != longhands::border_image_${name}::get_initial_specified_value() { + return Ok(()); + } + % endfor + + let all_equal = { + % for side in PHYSICAL_SIDES: + let border_${side}_width = self.border_${side}_width; + let border_${side}_style = self.border_${side}_style; + let border_${side}_color = self.border_${side}_color; + % endfor + + border_top_width == border_right_width && + border_right_width == border_bottom_width && + border_bottom_width == border_left_width && + + border_top_style == border_right_style && + border_right_style == border_bottom_style && + border_bottom_style == border_left_style && + + border_top_color == border_right_color && + border_right_color == border_bottom_color && + border_bottom_color == border_left_color + }; + + // If all longhands are all present, then all sides should be the same, + // so we can just one set of color/style/width + if !all_equal { + return Ok(()) + } + crate::values::specified::border::serialize_directional_border( + dest, + self.border_${side}_width, + self.border_${side}_style, + self.border_${side}_color + ) + } + } + + // Just use the same as border-left. The border shorthand can't accept + // any value that the sub-shorthand couldn't. + <% + border_left = "" + %> + impl SpecifiedValueInfo for Longhands { + const SUPPORTED_TYPES: u8 = ${border_left}::SUPPORTED_TYPES; + fn collect_completion_keywords(f: KeywordsCollectFn) { + ${border_left}::collect_completion_keywords(f); + } + } + + +<%helpers:shorthand + name="border-radius" + engines="gecko servo-2013 servo-2020" + sub_properties="${' '.join( + 'border-%s-radius' % (corner) + for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left'] + )}" + extra_prefixes="webkit" + spec="https://drafts.csswg.org/css-backgrounds/#border-radius" +> + use crate::values::generics::rect::Rect; + use crate::values::generics::border::BorderCornerRadius; + use crate::values::specified::border::BorderRadius; + use crate::parser::Parse; + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let radii = BorderRadius::parse(context, input)?; + Ok(expanded! { + border_top_left_radius: radii.top_left, + border_top_right_radius: radii.top_right, + border_bottom_right_radius: radii.bottom_right, + border_bottom_left_radius: radii.bottom_left, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + let LonghandsToSerialize { + border_top_left_radius: &BorderCornerRadius(ref tl), + border_top_right_radius: &BorderCornerRadius(ref tr), + border_bottom_right_radius: &BorderCornerRadius(ref br), + border_bottom_left_radius: &BorderCornerRadius(ref bl), + } = *self; + + + let widths = Rect::new(tl.width(), tr.width(), br.width(), bl.width()); + let heights = Rect::new(tl.height(), tr.height(), br.height(), bl.height()); + + BorderRadius::serialize_rects(widths, heights, dest) + } + } + + +<%helpers:shorthand + name="border-image" + engines="gecko servo-2013" + sub_properties="border-image-outset + border-image-repeat border-image-slice border-image-source border-image-width" + extra_prefixes="moz:layout.css.prefixes.border-image webkit" + spec="https://drafts.csswg.org/css-backgrounds-3/#border-image" +> + use crate::properties::longhands::{border_image_outset, border_image_repeat, border_image_slice}; + use crate::properties::longhands::{border_image_source, border_image_width}; + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + % for name in "outset repeat slice source width".split(): + let mut ${name} = border_image_${name}::get_initial_specified_value(); + % endfor + let mut any = false; + let mut parsed_slice = false; + let mut parsed_source = false; + let mut parsed_repeat = false; + loop { + if !parsed_slice { + if let Ok(value) = input.try_parse(|input| border_image_slice::parse(context, input)) { + parsed_slice = true; + any = true; + slice = value; + // Parse border image width and outset, if applicable. + let maybe_width_outset: Result<_, ParseError> = input.try_parse(|input| { + input.expect_delim('/')?; + + // Parse border image width, if applicable. + let w = input.try_parse(|input| border_image_width::parse(context, input)).ok(); + + // Parse border image outset if applicable. + let o = input.try_parse(|input| { + input.expect_delim('/')?; + border_image_outset::parse(context, input) + }).ok(); + if w.is_none() && o.is_none() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + Ok((w, o)) + }); + if let Ok((w, o)) = maybe_width_outset { + if let Some(w) = w { + width = w; + } + if let Some(o) = o { + outset = o; + } + } + continue; + } + } + % for name in "source repeat".split(): + if !parsed_${name} { + if let Ok(value) = input.try_parse(|input| border_image_${name}::parse(context, input)) { + ${name} = value; + parsed_${name} = true; + any = true; + continue + } + } + % endfor + break + } + if !any { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + Ok(expanded! { + % for name in "outset repeat slice source width".split(): + border_image_${name}: ${name}, + % endfor + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + let mut has_any = false; + % for name in "source slice outset width repeat".split(): + let has_${name} = *self.border_image_${name} != border_image_${name}::get_initial_specified_value(); + has_any = has_any || has_${name}; + % endfor + if has_source || !has_any { + self.border_image_source.to_css(dest)?; + if !has_any { + return Ok(()); + } + } + let needs_slice = has_slice || has_width || has_outset; + if needs_slice { + if has_source { + dest.write_char(' ')?; + } + self.border_image_slice.to_css(dest)?; + if has_width || has_outset { + dest.write_str(" /")?; + if has_width { + dest.write_char(' ')?; + self.border_image_width.to_css(dest)?; + } + if has_outset { + dest.write_str(" / ")?; + self.border_image_outset.to_css(dest)?; + } + } + } + if has_repeat { + if has_source || needs_slice { + dest.write_char(' ')?; + } + self.border_image_repeat.to_css(dest)?; + } + Ok(()) + } + } + + +% for axis in ["block", "inline"]: + % for prop in ["width", "style", "color"]: + <% + spec = "https://drafts.csswg.org/css-logical/#propdef-border-%s-%s" % (axis, prop) + %> + <%helpers:shorthand + engines="gecko servo-2013 servo-2020" + name="border-${axis}-${prop}" + sub_properties="${' '.join( + 'border-%s-%s-%s' % (axis, side, prop) + for side in ['start', 'end'] + )}" + spec="${spec}"> + + use crate::properties::longhands::border_${axis}_start_${prop}; + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let start_value = border_${axis}_start_${prop}::parse(context, input)?; + let end_value = + input.try_parse(|input| border_${axis}_start_${prop}::parse(context, input)) + .unwrap_or_else(|_| start_value.clone()); + + Ok(expanded! { + border_${axis}_start_${prop}: start_value, + border_${axis}_end_${prop}: end_value, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + self.border_${axis}_start_${prop}.to_css(dest)?; + + if self.border_${axis}_end_${prop} != self.border_${axis}_start_${prop} { + dest.write_char(' ')?; + self.border_${axis}_end_${prop}.to_css(dest)?; + } + + Ok(()) + } + } + + % endfor +% endfor + +% for axis in ["block", "inline"]: + <% + spec = "https://drafts.csswg.org/css-logical/#propdef-border-%s" % (axis) + %> + <%helpers:shorthand + name="border-${axis}" + engines="gecko servo-2013 servo-2020" + sub_properties="${' '.join( + 'border-%s-%s-width' % (axis, side) + for side in ['start', 'end'] + )} ${' '.join( + 'border-%s-%s-style' % (axis, side) + for side in ['start', 'end'] + )} ${' '.join( + 'border-%s-%s-color' % (axis, side) + for side in ['start', 'end'] + )}" + spec="${spec}"> + + use crate::properties::shorthands::border_${axis}_start; + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let start_value = border_${axis}_start::parse_value(context, input)?; + Ok(expanded! { + border_${axis}_start_width: start_value.border_${axis}_start_width.clone(), + border_${axis}_end_width: start_value.border_${axis}_start_width, + border_${axis}_start_style: start_value.border_${axis}_start_style.clone(), + border_${axis}_end_style: start_value.border_${axis}_start_style, + border_${axis}_start_color: start_value.border_${axis}_start_color.clone(), + border_${axis}_end_color: start_value.border_${axis}_start_color, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + crate::values::specified::border::serialize_directional_border( + dest, + self.border_${axis}_start_width, + self.border_${axis}_start_style, + self.border_${axis}_start_color + ) + } + } + +% endfor -- cgit v1.2.3