tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

border.mako.rs (19066B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 <%namespace name="helpers" file="/helpers.mako.rs" />
      6 <% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>
      7 
      8 ${helpers.four_sides_shorthand(
      9    "border-color",
     10    "border-%s-color",
     11    "specified::Color::parse",
     12    engines="gecko servo",
     13    spec="https://drafts.csswg.org/css-backgrounds/#border-color",
     14    allow_quirks="Yes",
     15 )}
     16 
     17 ${helpers.four_sides_shorthand(
     18    "border-style",
     19    "border-%s-style",
     20    engines="gecko servo",
     21    spec="https://drafts.csswg.org/css-backgrounds/#border-style",
     22 )}
     23 
     24 <%helpers:shorthand
     25    name="border-width"
     26    engines="gecko servo"
     27    sub_properties="${
     28        ' '.join('border-%s-width' % side
     29                 for side in PHYSICAL_SIDES)}"
     30    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
     31    use crate::values::generics::rect::Rect;
     32    use crate::values::specified::{AllowQuirks, BorderSideWidth};
     33 
     34    pub fn parse_value<'i, 't>(
     35        context: &ParserContext,
     36        input: &mut Parser<'i, 't>,
     37    ) -> Result<Longhands, ParseError<'i>> {
     38        let rect = Rect::parse_with(context, input, |_, i| {
     39            BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes)
     40        })?;
     41        Ok(expanded! {
     42            border_top_width: rect.0,
     43            border_right_width: rect.1,
     44            border_bottom_width: rect.2,
     45            border_left_width: rect.3,
     46        })
     47    }
     48 
     49    impl<'a> ToCss for LonghandsToSerialize<'a>  {
     50        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
     51            % for side in PHYSICAL_SIDES:
     52            let ${side} = &self.border_${side}_width;
     53            % endfor
     54            Rect::new(top, right, bottom, left).to_css(dest)
     55        }
     56    }
     57 </%helpers:shorthand>
     58 
     59 
     60 pub fn parse_border<'i, 't>(
     61    context: &ParserContext,
     62    input: &mut Parser<'i, 't>,
     63 ) -> Result<(specified::Color, specified::BorderStyle, specified::BorderSideWidth), ParseError<'i>> {
     64    use crate::values::specified::{Color, BorderStyle, BorderSideWidth};
     65    let _unused = context;
     66    let mut color = None;
     67    let mut style = None;
     68    let mut width = None;
     69    let mut any = false;
     70    loop {
     71        if width.is_none() {
     72            if let Ok(value) = input.try_parse(|i| BorderSideWidth::parse(context, i)) {
     73                width = Some(value);
     74                any = true;
     75            }
     76        }
     77        if style.is_none() {
     78            if let Ok(value) = input.try_parse(BorderStyle::parse) {
     79                style = Some(value);
     80                any = true;
     81                continue
     82            }
     83        }
     84        if color.is_none() {
     85            if let Ok(value) = input.try_parse(|i| Color::parse(context, i)) {
     86                color = Some(value);
     87                any = true;
     88                continue
     89            }
     90        }
     91        break
     92    }
     93    if !any {
     94        return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
     95    }
     96    Ok((color.unwrap_or(Color::CurrentColor), style.unwrap_or(BorderStyle::None), width.unwrap_or(BorderSideWidth::medium())))
     97 }
     98 
     99 % for side, logical in ALL_SIDES:
    100    <%
    101        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
    102        if logical:
    103            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    104    %>
    105    <%helpers:shorthand
    106        name="border-${side}"
    107        engines="gecko servo"
    108        sub_properties="${' '.join(
    109            'border-%s-%s' % (side, prop)
    110            for prop in ['width', 'style', 'color']
    111        )}"
    112        aliases="${maybe_moz_logical_alias(engine, (side, logical), '-moz-border-%s')}"
    113        spec="${spec}">
    114 
    115    pub fn parse_value<'i, 't>(
    116        context: &ParserContext,
    117        input: &mut Parser<'i, 't>,
    118    ) -> Result<Longhands, ParseError<'i>> {
    119        let (color, style, width) = super::parse_border(context, input)?;
    120        Ok(expanded! {
    121            border_${to_rust_ident(side)}_color: color,
    122            border_${to_rust_ident(side)}_style: style,
    123            border_${to_rust_ident(side)}_width: width
    124        })
    125    }
    126 
    127    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    128        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    129            crate::values::specified::border::serialize_directional_border(
    130                dest,
    131                self.border_${to_rust_ident(side)}_width,
    132                self.border_${to_rust_ident(side)}_style,
    133                self.border_${to_rust_ident(side)}_color
    134            )
    135        }
    136    }
    137 
    138    </%helpers:shorthand>
    139 % endfor
    140 
    141 <%helpers:shorthand name="border"
    142    engines="gecko servo"
    143    sub_properties="${' '.join('border-%s-%s' % (side, prop)
    144        for side in PHYSICAL_SIDES for prop in ['width', 'style', 'color']
    145        )}
    146        ${' '.join('border-image-%s' % name
    147        for name in ['outset', 'repeat', 'slice', 'source', 'width'])}"
    148    derive_value_info="False"
    149    spec="https://drafts.csswg.org/css-backgrounds/#border">
    150 
    151    pub fn parse_value<'i, 't>(
    152        context: &ParserContext,
    153        input: &mut Parser<'i, 't>,
    154    ) -> Result<Longhands, ParseError<'i>> {
    155        use crate::properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    156        use crate::properties::longhands::{border_image_source, border_image_width};
    157 
    158        let (color, style, width) = super::parse_border(context, input)?;
    159        Ok(expanded! {
    160            % for side in PHYSICAL_SIDES:
    161                border_${side}_color: color.clone(),
    162                border_${side}_style: style,
    163                border_${side}_width: width.clone(),
    164            % endfor
    165 
    166            // The ‘border’ shorthand resets ‘border-image’ to its initial value.
    167            // See https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands
    168            % for name in "outset repeat slice source width".split():
    169                border_image_${name}: border_image_${name}::get_initial_specified_value(),
    170            % endfor
    171        })
    172    }
    173 
    174    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    175        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    176            use crate::properties::longhands;
    177 
    178            // If any of the border-image longhands differ from their initial specified values we should not
    179            // invoke serialize_directional_border(), so there is no point in continuing on to compute all_equal.
    180            % for name in "outset repeat slice source width".split():
    181                if *self.border_image_${name} != longhands::border_image_${name}::get_initial_specified_value() {
    182                    return Ok(());
    183                }
    184            % endfor
    185 
    186            let all_equal = {
    187                % for side in PHYSICAL_SIDES:
    188                  let border_${side}_width = self.border_${side}_width;
    189                  let border_${side}_style = self.border_${side}_style;
    190                  let border_${side}_color = self.border_${side}_color;
    191                % endfor
    192 
    193                border_top_width == border_right_width &&
    194                border_right_width == border_bottom_width &&
    195                border_bottom_width == border_left_width &&
    196 
    197                border_top_style == border_right_style &&
    198                border_right_style == border_bottom_style &&
    199                border_bottom_style == border_left_style &&
    200 
    201                border_top_color == border_right_color &&
    202                border_right_color == border_bottom_color &&
    203                border_bottom_color == border_left_color
    204            };
    205 
    206            // If all longhands are all present, then all sides should be the same,
    207            // so we can just one set of color/style/width
    208            if !all_equal {
    209                return Ok(())
    210            }
    211            crate::values::specified::border::serialize_directional_border(
    212                dest,
    213                self.border_${side}_width,
    214                self.border_${side}_style,
    215                self.border_${side}_color
    216            )
    217        }
    218    }
    219 
    220    // Just use the same as border-left. The border shorthand can't accept
    221    // any value that the sub-shorthand couldn't.
    222    <%
    223        border_left = "<crate::properties::shorthands::border_left::Longhands as SpecifiedValueInfo>"
    224    %>
    225    impl SpecifiedValueInfo for Longhands {
    226        const SUPPORTED_TYPES: u8 = ${border_left}::SUPPORTED_TYPES;
    227        fn collect_completion_keywords(f: KeywordsCollectFn) {
    228            ${border_left}::collect_completion_keywords(f);
    229        }
    230    }
    231 </%helpers:shorthand>
    232 
    233 <%helpers:shorthand
    234    name="border-radius"
    235    engines="gecko servo"
    236    sub_properties="${' '.join(
    237        'border-%s-radius' % (corner)
    238         for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
    239    )}"
    240    extra_prefixes="webkit"
    241    spec="https://drafts.csswg.org/css-backgrounds/#border-radius"
    242 >
    243    use crate::values::generics::rect::Rect;
    244    use crate::values::generics::border::BorderCornerRadius;
    245    use crate::values::specified::border::BorderRadius;
    246    use crate::parser::Parse;
    247 
    248    pub fn parse_value<'i, 't>(
    249        context: &ParserContext,
    250        input: &mut Parser<'i, 't>,
    251    ) -> Result<Longhands, ParseError<'i>> {
    252        let radii = BorderRadius::parse(context, input)?;
    253        Ok(expanded! {
    254            border_top_left_radius: radii.top_left,
    255            border_top_right_radius: radii.top_right,
    256            border_bottom_right_radius: radii.bottom_right,
    257            border_bottom_left_radius: radii.bottom_left,
    258        })
    259    }
    260 
    261    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    262        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    263            let LonghandsToSerialize {
    264                border_top_left_radius: &BorderCornerRadius(ref tl),
    265                border_top_right_radius: &BorderCornerRadius(ref tr),
    266                border_bottom_right_radius: &BorderCornerRadius(ref br),
    267                border_bottom_left_radius: &BorderCornerRadius(ref bl),
    268            } = *self;
    269 
    270 
    271            let widths = Rect::new(tl.width(), tr.width(), br.width(), bl.width());
    272            let heights = Rect::new(tl.height(), tr.height(), br.height(), bl.height());
    273 
    274            BorderRadius::serialize_rects(widths, heights, dest)
    275        }
    276    }
    277 </%helpers:shorthand>
    278 
    279 <%helpers:shorthand
    280    name="border-image"
    281    engines="gecko servo"
    282    sub_properties="border-image-outset
    283        border-image-repeat border-image-slice border-image-source border-image-width"
    284    extra_prefixes="moz:layout.css.prefixes.border-image webkit"
    285    spec="https://drafts.csswg.org/css-backgrounds-3/#border-image"
    286 >
    287    use crate::properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    288    use crate::properties::longhands::{border_image_source, border_image_width};
    289 
    290    pub fn parse_value<'i, 't>(
    291        context: &ParserContext,
    292        input: &mut Parser<'i, 't>,
    293    ) -> Result<Longhands, ParseError<'i>> {
    294        % for name in "outset repeat slice source width".split():
    295        let mut ${name} = border_image_${name}::get_initial_specified_value();
    296        % endfor
    297        let mut any = false;
    298        let mut parsed_slice = false;
    299        let mut parsed_source = false;
    300        let mut parsed_repeat = false;
    301        loop {
    302            if !parsed_slice {
    303                if let Ok(value) = input.try_parse(|input| border_image_slice::parse(context, input)) {
    304                    parsed_slice = true;
    305                    any = true;
    306                    slice = value;
    307                    // Parse border image width and outset, if applicable.
    308                    let maybe_width_outset: Result<_, ParseError> = input.try_parse(|input| {
    309                        input.expect_delim('/')?;
    310 
    311                        // Parse border image width, if applicable.
    312                        let w = input.try_parse(|input| border_image_width::parse(context, input)).ok();
    313 
    314                        // Parse border image outset if applicable.
    315                        let o = input.try_parse(|input| {
    316                            input.expect_delim('/')?;
    317                            border_image_outset::parse(context, input)
    318                        }).ok();
    319                        if w.is_none() && o.is_none() {
    320                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    321                        }
    322                        Ok((w, o))
    323                    });
    324                    if let Ok((w, o)) = maybe_width_outset {
    325                        if let Some(w) = w {
    326                            width = w;
    327                        }
    328                        if let Some(o) = o {
    329                            outset = o;
    330                        }
    331                    }
    332                    continue;
    333                }
    334            }
    335            % for name in "source repeat".split():
    336                if !parsed_${name} {
    337                    if let Ok(value) = input.try_parse(|input| border_image_${name}::parse(context, input)) {
    338                        ${name} = value;
    339                        parsed_${name} = true;
    340                        any = true;
    341                        continue
    342                    }
    343                }
    344            % endfor
    345            break
    346        }
    347        if !any {
    348            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    349        }
    350        Ok(expanded! {
    351            % for name in "outset repeat slice source width".split():
    352                border_image_${name}: ${name},
    353            % endfor
    354         })
    355    }
    356 
    357    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    358        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    359            let mut has_any = false;
    360            % for name in "source slice outset width repeat".split():
    361            let has_${name} = *self.border_image_${name} != border_image_${name}::get_initial_specified_value();
    362            has_any = has_any || has_${name};
    363            % endfor
    364            if has_source || !has_any {
    365                self.border_image_source.to_css(dest)?;
    366                if !has_any {
    367                    return Ok(());
    368                }
    369            }
    370            let needs_slice = has_slice || has_width || has_outset;
    371            if needs_slice {
    372                if has_source {
    373                    dest.write_char(' ')?;
    374                }
    375                self.border_image_slice.to_css(dest)?;
    376                if has_width || has_outset {
    377                    dest.write_str(" /")?;
    378                    if has_width {
    379                        dest.write_char(' ')?;
    380                        self.border_image_width.to_css(dest)?;
    381                    }
    382                    if has_outset {
    383                        dest.write_str(" / ")?;
    384                        self.border_image_outset.to_css(dest)?;
    385                    }
    386                }
    387            }
    388            if has_repeat {
    389                if has_source || needs_slice {
    390                    dest.write_char(' ')?;
    391                }
    392                self.border_image_repeat.to_css(dest)?;
    393            }
    394            Ok(())
    395        }
    396    }
    397 </%helpers:shorthand>
    398 
    399 % for axis in ["block", "inline"]:
    400    % for prop in ["width", "style", "color"]:
    401        <%
    402            spec = "https://drafts.csswg.org/css-logical/#propdef-border-%s-%s" % (axis, prop)
    403        %>
    404        <%helpers:shorthand
    405            engines="gecko servo"
    406            name="border-${axis}-${prop}"
    407            sub_properties="${' '.join(
    408                'border-%s-%s-%s' % (axis, side, prop)
    409                for side in ['start', 'end']
    410            )}"
    411            spec="${spec}">
    412 
    413            use crate::properties::longhands::border_${axis}_start_${prop};
    414            pub fn parse_value<'i, 't>(
    415                context: &ParserContext,
    416                input: &mut Parser<'i, 't>,
    417            ) -> Result<Longhands, ParseError<'i>> {
    418                let start_value = border_${axis}_start_${prop}::parse(context, input)?;
    419                let end_value =
    420                    input.try_parse(|input| border_${axis}_start_${prop}::parse(context, input))
    421                        .unwrap_or_else(|_| start_value.clone());
    422 
    423                Ok(expanded! {
    424                    border_${axis}_start_${prop}: start_value,
    425                    border_${axis}_end_${prop}: end_value,
    426                })
    427            }
    428 
    429            impl<'a> ToCss for LonghandsToSerialize<'a>  {
    430                fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    431                    self.border_${axis}_start_${prop}.to_css(dest)?;
    432 
    433                    if self.border_${axis}_end_${prop} != self.border_${axis}_start_${prop} {
    434                        dest.write_char(' ')?;
    435                        self.border_${axis}_end_${prop}.to_css(dest)?;
    436                    }
    437 
    438                    Ok(())
    439                }
    440            }
    441        </%helpers:shorthand>
    442    % endfor
    443 % endfor
    444 
    445 % for axis in ["block", "inline"]:
    446    <%
    447        spec = "https://drafts.csswg.org/css-logical/#propdef-border-%s" % (axis)
    448    %>
    449    <%helpers:shorthand
    450        name="border-${axis}"
    451        engines="gecko servo"
    452        sub_properties="${' '.join(
    453            'border-%s-%s-width' % (axis, side)
    454            for side in ['start', 'end']
    455        )} ${' '.join(
    456            'border-%s-%s-style' % (axis, side)
    457            for side in ['start', 'end']
    458        )} ${' '.join(
    459            'border-%s-%s-color' % (axis, side)
    460            for side in ['start', 'end']
    461        )}"
    462        spec="${spec}">
    463 
    464        use crate::properties::shorthands::border_${axis}_start;
    465        pub fn parse_value<'i, 't>(
    466            context: &ParserContext,
    467            input: &mut Parser<'i, 't>,
    468        ) -> Result<Longhands, ParseError<'i>> {
    469            let start_value = border_${axis}_start::parse_value(context, input)?;
    470            Ok(expanded! {
    471                border_${axis}_start_width: start_value.border_${axis}_start_width.clone(),
    472                border_${axis}_end_width: start_value.border_${axis}_start_width,
    473                border_${axis}_start_style: start_value.border_${axis}_start_style.clone(),
    474                border_${axis}_end_style: start_value.border_${axis}_start_style,
    475                border_${axis}_start_color: start_value.border_${axis}_start_color.clone(),
    476                border_${axis}_end_color: start_value.border_${axis}_start_color,
    477            })
    478        }
    479 
    480        impl<'a> ToCss for LonghandsToSerialize<'a>  {
    481            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    482                crate::values::specified::border::serialize_directional_border(
    483                    dest,
    484                    self.border_${axis}_start_width,
    485                    self.border_${axis}_start_style,
    486                    self.border_${axis}_start_color
    487                )
    488            }
    489        }
    490    </%helpers:shorthand>
    491 % endfor