tor-browser

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

background.mako.rs (12565B)


      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 
      7 // TODO: other background-* properties
      8 <%helpers:shorthand name="background"
      9                    engines="gecko servo"
     10                    sub_properties="background-color background-position-x background-position-y background-repeat
     11                                    background-attachment background-image background-size background-origin
     12                                    background-clip"
     13                    spec="https://drafts.csswg.org/css-backgrounds/#the-background">
     14    use crate::properties::longhands::{background_position_x, background_position_y, background_repeat};
     15    use crate::properties::longhands::{background_attachment, background_color, background_image, background_size, background_origin};
     16    use crate::properties::longhands::background_clip;
     17    use crate::properties::longhands::background_clip::single_value::computed_value::T as Clip;
     18    use crate::properties::longhands::background_origin::single_value::computed_value::T as Origin;
     19    use crate::values::specified::{AllowQuirks, Color, Position, PositionComponent};
     20    use crate::parser::Parse;
     21 
     22    // FIXME(emilio): Should be the same type!
     23    impl From<background_origin::single_value::SpecifiedValue> for background_clip::single_value::SpecifiedValue {
     24        fn from(origin: background_origin::single_value::SpecifiedValue) ->
     25            background_clip::single_value::SpecifiedValue {
     26            match origin {
     27                background_origin::single_value::SpecifiedValue::ContentBox =>
     28                    background_clip::single_value::SpecifiedValue::ContentBox,
     29                background_origin::single_value::SpecifiedValue::PaddingBox =>
     30                    background_clip::single_value::SpecifiedValue::PaddingBox,
     31                background_origin::single_value::SpecifiedValue::BorderBox =>
     32                    background_clip::single_value::SpecifiedValue::BorderBox,
     33            }
     34        }
     35    }
     36 
     37    pub fn parse_value<'i, 't>(
     38        context: &ParserContext,
     39        input: &mut Parser<'i, 't>,
     40    ) -> Result<Longhands, ParseError<'i>> {
     41        let mut background_color = None;
     42 
     43        % for name in "image position_x position_y repeat size attachment origin clip".split():
     44        // Vec grows from 0 to 4 by default on first push().  So allocate with
     45        // capacity 1, so in the common case of only one item we don't way
     46        // overallocate, then shrink.  Note that we always push at least one
     47        // item if parsing succeeds.
     48        let mut background_${name} = Vec::with_capacity(1);
     49        % endfor
     50        input.parse_comma_separated(|input| {
     51            // background-color can only be in the last element, so if it
     52            // is parsed anywhere before, the value is invalid.
     53            if background_color.is_some() {
     54                return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
     55            }
     56 
     57            % for name in "image position repeat size attachment origin clip".split():
     58                let mut ${name} = None;
     59            % endfor
     60            loop {
     61                if background_color.is_none() {
     62                    if let Ok(value) = input.try_parse(|i| Color::parse(context, i)) {
     63                        background_color = Some(value);
     64                        continue
     65                    }
     66                }
     67                if position.is_none() {
     68                    if let Ok(value) = input.try_parse(|input| {
     69                        Position::parse_three_value_quirky(context, input, AllowQuirks::No)
     70                    }) {
     71                        position = Some(value);
     72 
     73                        // Parse background size, if applicable.
     74                        size = input.try_parse(|input| {
     75                            input.expect_delim('/')?;
     76                            background_size::single_value::parse(context, input)
     77                        }).ok();
     78 
     79                        continue
     80                    }
     81                }
     82                % for name in "image repeat attachment origin clip".split():
     83                    if ${name}.is_none() {
     84                        if let Ok(value) = input.try_parse(|input| background_${name}::single_value
     85                                                                               ::parse(context, input)) {
     86                            ${name} = Some(value);
     87                            continue
     88                        }
     89                    }
     90                % endfor
     91                break
     92            }
     93            if clip.is_none() {
     94                if let Some(origin) = origin {
     95                    clip = Some(background_clip::single_value::SpecifiedValue::from(origin));
     96                }
     97            }
     98            let mut any = false;
     99            % for name in "image position repeat size attachment origin clip".split():
    100                any = any || ${name}.is_some();
    101            % endfor
    102            any = any || background_color.is_some();
    103            if any {
    104                if let Some(position) = position {
    105                    background_position_x.push(position.horizontal);
    106                    background_position_y.push(position.vertical);
    107                } else {
    108                    background_position_x.push(PositionComponent::zero());
    109                    background_position_y.push(PositionComponent::zero());
    110                }
    111                % for name in "image repeat size attachment origin clip".split():
    112                    if let Some(bg_${name}) = ${name} {
    113                        background_${name}.push(bg_${name});
    114                    } else {
    115                        background_${name}.push(background_${name}::single_value
    116                                                                    ::get_initial_specified_value());
    117                    }
    118                % endfor
    119                Ok(())
    120            } else {
    121                Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    122            }
    123        })?;
    124 
    125        Ok(expanded! {
    126             background_color: background_color.unwrap_or(Color::transparent()),
    127             % for name in "image position_x position_y repeat size attachment origin clip".split():
    128             background_${name}: background_${name}::SpecifiedValue(background_${name}.into()),
    129             % endfor
    130         })
    131    }
    132 
    133    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    134        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    135            let len = self.background_image.0.len();
    136            // There should be at least one declared value
    137            if len == 0 {
    138                return Ok(());
    139            }
    140 
    141            // If a value list length is differs then we don't do a shorthand serialization.
    142            // The exceptions to this is color which appears once only and is serialized
    143            // with the last item.
    144            % for name in "image position_x position_y size repeat origin clip attachment".split():
    145                if len != self.background_${name}.0.len() {
    146                    return Ok(());
    147                }
    148            % endfor
    149 
    150            for i in 0..len {
    151                % for name in "image position_x position_y repeat size attachment origin clip".split():
    152                    let ${name} = &self.background_${name}.0[i];
    153                % endfor
    154 
    155                if i != 0 {
    156                    dest.write_str(", ")?;
    157                }
    158 
    159                let mut wrote_value = false;
    160 
    161                if i == len - 1 {
    162                    if *self.background_color != background_color::get_initial_specified_value() {
    163                        self.background_color.to_css(dest)?;
    164                        wrote_value = true;
    165                    }
    166                }
    167 
    168                if *image != background_image::single_value::get_initial_specified_value() {
    169                    if wrote_value {
    170                        dest.write_char(' ')?;
    171                    }
    172                    image.to_css(dest)?;
    173                    wrote_value = true;
    174                }
    175 
    176                // Size is only valid after a position so when there is a
    177                // non-initial size we must also serialize position
    178                if *position_x != PositionComponent::zero() ||
    179                    *position_y != PositionComponent::zero() ||
    180                    *size != background_size::single_value::get_initial_specified_value()
    181                {
    182                    if wrote_value {
    183                        dest.write_char(' ')?;
    184                    }
    185 
    186                    Position {
    187                        horizontal: position_x.clone(),
    188                        vertical: position_y.clone()
    189                    }.to_css(dest)?;
    190 
    191                    wrote_value = true;
    192 
    193                    if *size != background_size::single_value::get_initial_specified_value() {
    194                        dest.write_str(" / ")?;
    195                        size.to_css(dest)?;
    196                    }
    197                }
    198 
    199                % for name in "repeat attachment".split():
    200                    if *${name} != background_${name}::single_value::get_initial_specified_value() {
    201                        if wrote_value {
    202                            dest.write_char(' ')?;
    203                        }
    204                        ${name}.to_css(dest)?;
    205                        wrote_value = true;
    206                    }
    207                % endfor
    208 
    209                if *origin != Origin::PaddingBox || *clip != Clip::BorderBox {
    210                    if wrote_value {
    211                        dest.write_char(' ')?;
    212                    }
    213                    origin.to_css(dest)?;
    214                    if *clip != From::from(*origin) {
    215                        dest.write_char(' ')?;
    216                        clip.to_css(dest)?;
    217                    }
    218 
    219                    wrote_value = true;
    220                }
    221 
    222                if !wrote_value {
    223                    image.to_css(dest)?;
    224                }
    225            }
    226 
    227            Ok(())
    228        }
    229    }
    230 </%helpers:shorthand>
    231 
    232 <%helpers:shorthand name="background-position"
    233                    engines="gecko servo"
    234                    sub_properties="background-position-x background-position-y"
    235                    spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position">
    236    use crate::properties::longhands::{background_position_x, background_position_y};
    237    use crate::values::specified::AllowQuirks;
    238    use crate::values::specified::position::Position;
    239 
    240    pub fn parse_value<'i, 't>(
    241        context: &ParserContext,
    242        input: &mut Parser<'i, 't>,
    243    ) -> Result<Longhands, ParseError<'i>> {
    244        // Vec grows from 0 to 4 by default on first push().  So allocate with
    245        // capacity 1, so in the common case of only one item we don't way
    246        // overallocate, then shrink.  Note that we always push at least one
    247        // item if parsing succeeds.
    248        let mut position_x = Vec::with_capacity(1);
    249        let mut position_y = Vec::with_capacity(1);
    250        let mut any = false;
    251 
    252        input.parse_comma_separated(|input| {
    253            let value = Position::parse_three_value_quirky(context, input, AllowQuirks::Yes)?;
    254            position_x.push(value.horizontal);
    255            position_y.push(value.vertical);
    256            any = true;
    257            Ok(())
    258        })?;
    259        if !any {
    260            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
    261        }
    262 
    263        Ok(expanded! {
    264            background_position_x: background_position_x::SpecifiedValue(position_x.into()),
    265            background_position_y: background_position_y::SpecifiedValue(position_y.into()),
    266        })
    267    }
    268 
    269    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    270        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    271            let len = self.background_position_x.0.len();
    272            if len == 0 || len != self.background_position_y.0.len() {
    273                return Ok(());
    274            }
    275            for i in 0..len {
    276                Position {
    277                    horizontal: self.background_position_x.0[i].clone(),
    278                    vertical: self.background_position_y.0[i].clone()
    279                }.to_css(dest)?;
    280 
    281                if i < len - 1 {
    282                    dest.write_str(", ")?;
    283                }
    284            }
    285            Ok(())
    286        }
    287    }
    288 </%helpers:shorthand>