background.rs (4479B)
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 //! Specified types for CSS values related to backgrounds. 6 7 use crate::derives::*; 8 use crate::parser::{Parse, ParserContext}; 9 use crate::values::generics::background::BackgroundSize as GenericBackgroundSize; 10 use crate::values::specified::length::{ 11 NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto, 12 }; 13 use cssparser::{match_ignore_ascii_case, Parser}; 14 use selectors::parser::SelectorParseErrorKind; 15 use std::fmt::{self, Write}; 16 use style_traits::{CssWriter, ParseError, ToCss}; 17 18 /// A specified value for the `background-size` property. 19 pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthPercentage>; 20 21 impl Parse for BackgroundSize { 22 fn parse<'i, 't>( 23 context: &ParserContext, 24 input: &mut Parser<'i, 't>, 25 ) -> Result<Self, ParseError<'i>> { 26 if let Ok(width) = input.try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i)) 27 { 28 let height = input 29 .try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i)) 30 .unwrap_or(NonNegativeLengthPercentageOrAuto::auto()); 31 return Ok(GenericBackgroundSize::ExplicitSize { width, height }); 32 } 33 Ok(try_match_ident_ignore_ascii_case! { input, 34 "cover" => GenericBackgroundSize::Cover, 35 "contain" => GenericBackgroundSize::Contain, 36 }) 37 } 38 } 39 40 /// One of the keywords for `background-repeat`. 41 #[derive( 42 Clone, 43 Copy, 44 Debug, 45 Eq, 46 MallocSizeOf, 47 Parse, 48 PartialEq, 49 SpecifiedValueInfo, 50 ToComputedValue, 51 ToCss, 52 ToResolvedValue, 53 ToShmem, 54 )] 55 #[allow(missing_docs)] 56 #[value_info(other_values = "repeat-x,repeat-y")] 57 pub enum BackgroundRepeatKeyword { 58 Repeat, 59 Space, 60 Round, 61 NoRepeat, 62 } 63 64 /// The value of the `background-repeat` property, with `repeat-x` / `repeat-y` 65 /// represented as the combination of `no-repeat` and `repeat` in the opposite 66 /// axes. 67 /// 68 /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat 69 #[derive( 70 Clone, 71 Debug, 72 MallocSizeOf, 73 PartialEq, 74 SpecifiedValueInfo, 75 ToComputedValue, 76 ToResolvedValue, 77 ToShmem, 78 )] 79 pub struct BackgroundRepeat(pub BackgroundRepeatKeyword, pub BackgroundRepeatKeyword); 80 81 impl BackgroundRepeat { 82 /// Returns the `repeat repeat` value. 83 pub fn repeat() -> Self { 84 BackgroundRepeat( 85 BackgroundRepeatKeyword::Repeat, 86 BackgroundRepeatKeyword::Repeat, 87 ) 88 } 89 } 90 91 impl ToCss for BackgroundRepeat { 92 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 93 where 94 W: Write, 95 { 96 match (self.0, self.1) { 97 (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) => { 98 dest.write_str("repeat-x") 99 }, 100 (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) => { 101 dest.write_str("repeat-y") 102 }, 103 (horizontal, vertical) => { 104 horizontal.to_css(dest)?; 105 if horizontal != vertical { 106 dest.write_char(' ')?; 107 vertical.to_css(dest)?; 108 } 109 Ok(()) 110 }, 111 } 112 } 113 } 114 115 impl Parse for BackgroundRepeat { 116 fn parse<'i, 't>( 117 _context: &ParserContext, 118 input: &mut Parser<'i, 't>, 119 ) -> Result<Self, ParseError<'i>> { 120 let ident = input.expect_ident_cloned()?; 121 122 match_ignore_ascii_case! { &ident, 123 "repeat-x" => { 124 return Ok(BackgroundRepeat(BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat)); 125 }, 126 "repeat-y" => { 127 return Ok(BackgroundRepeat(BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat)); 128 }, 129 _ => {}, 130 } 131 132 let horizontal = match BackgroundRepeatKeyword::from_ident(&ident) { 133 Ok(h) => h, 134 Err(()) => { 135 return Err( 136 input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) 137 ); 138 }, 139 }; 140 141 let vertical = input.try_parse(BackgroundRepeatKeyword::parse).ok(); 142 Ok(BackgroundRepeat(horizontal, vertical.unwrap_or(horizontal))) 143 } 144 }