resolution.rs (4089B)
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 //! Resolution values: 6 //! 7 //! https://drafts.csswg.org/css-values/#resolution 8 9 use crate::derives::*; 10 use crate::parser::{Parse, ParserContext}; 11 use crate::values::specified::CalcNode; 12 use crate::values::CSSFloat; 13 use cssparser::{match_ignore_ascii_case, Parser, Token}; 14 use std::fmt::{self, Write}; 15 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; 16 17 /// A specified resolution. 18 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] 19 pub struct Resolution { 20 value: CSSFloat, 21 unit: ResolutionUnit, 22 was_calc: bool, 23 } 24 25 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] 26 enum ResolutionUnit { 27 /// Dots per inch. 28 Dpi, 29 /// An alias unit for dots per pixel. 30 X, 31 /// Dots per pixel. 32 Dppx, 33 /// Dots per centimeter. 34 Dpcm, 35 } 36 37 impl ResolutionUnit { 38 fn as_str(self) -> &'static str { 39 match self { 40 Self::Dpi => "dpi", 41 Self::X => "x", 42 Self::Dppx => "dppx", 43 Self::Dpcm => "dpcm", 44 } 45 } 46 } 47 48 impl Resolution { 49 /// Returns a resolution value from dppx units. 50 pub fn from_dppx(value: CSSFloat) -> Self { 51 Self { 52 value, 53 unit: ResolutionUnit::Dppx, 54 was_calc: false, 55 } 56 } 57 58 /// Returns a resolution value from dppx units. 59 pub fn from_x(value: CSSFloat) -> Self { 60 Self { 61 value, 62 unit: ResolutionUnit::X, 63 was_calc: false, 64 } 65 } 66 67 /// Returns a resolution value from dppx units. 68 pub fn from_dppx_calc(value: CSSFloat) -> Self { 69 Self { 70 value, 71 unit: ResolutionUnit::Dppx, 72 was_calc: true, 73 } 74 } 75 76 /// Convert this resolution value to dppx units. 77 pub fn dppx(&self) -> CSSFloat { 78 match self.unit { 79 ResolutionUnit::X | ResolutionUnit::Dppx => self.value, 80 _ => self.dpi() / 96.0, 81 } 82 } 83 84 /// Convert this resolution value to dpi units. 85 pub fn dpi(&self) -> CSSFloat { 86 match self.unit { 87 ResolutionUnit::Dpi => self.value, 88 ResolutionUnit::X | ResolutionUnit::Dppx => self.value * 96.0, 89 ResolutionUnit::Dpcm => self.value * 2.54, 90 } 91 } 92 93 /// Parse a resolution given a value and unit. 94 pub fn parse_dimension<'i, 't>(value: CSSFloat, unit: &str) -> Result<Self, ()> { 95 let unit = match_ignore_ascii_case! { &unit, 96 "dpi" => ResolutionUnit::Dpi, 97 "dppx" => ResolutionUnit::Dppx, 98 "dpcm" => ResolutionUnit::Dpcm, 99 "x" => ResolutionUnit::X, 100 _ => return Err(()) 101 }; 102 Ok(Self { 103 value, 104 unit, 105 was_calc: false, 106 }) 107 } 108 } 109 110 impl ToCss for Resolution { 111 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 112 where 113 W: Write, 114 { 115 crate::values::serialize_specified_dimension( 116 self.value, 117 self.unit.as_str(), 118 self.was_calc, 119 dest, 120 ) 121 } 122 } 123 124 impl Parse for Resolution { 125 fn parse<'i, 't>( 126 context: &ParserContext, 127 input: &mut Parser<'i, 't>, 128 ) -> Result<Self, ParseError<'i>> { 129 let location = input.current_source_location(); 130 match *input.next()? { 131 Token::Dimension { 132 value, ref unit, .. 133 } if value >= 0. => Self::parse_dimension(value, unit) 134 .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)), 135 Token::Function(ref name) => { 136 let function = CalcNode::math_function(context, name, location)?; 137 CalcNode::parse_resolution(context, input, function) 138 }, 139 ref t => return Err(location.new_unexpected_token_error(t.clone())), 140 } 141 } 142 }