style/values/specified/
resolution.rs1use crate::derives::*;
10use crate::parser::{Parse, ParserContext};
11use crate::values::specified::CalcNode;
12use crate::values::CSSFloat;
13use cssparser::{match_ignore_ascii_case, Parser, Token};
14use std::fmt::{self, Write};
15use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
16
17#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
19pub struct Resolution {
20 value: CSSFloat,
21 unit: ResolutionUnit,
22 was_calc: bool,
23}
24
25#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
26enum ResolutionUnit {
27 Dpi,
29 X,
31 Dppx,
33 Dpcm,
35}
36
37impl 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
48impl Resolution {
49 pub fn from_dppx(value: CSSFloat) -> Self {
51 Self {
52 value,
53 unit: ResolutionUnit::Dppx,
54 was_calc: false,
55 }
56 }
57
58 pub fn from_x(value: CSSFloat) -> Self {
60 Self {
61 value,
62 unit: ResolutionUnit::X,
63 was_calc: false,
64 }
65 }
66
67 pub fn from_dppx_calc(value: CSSFloat) -> Self {
69 Self {
70 value,
71 unit: ResolutionUnit::Dppx,
72 was_calc: true,
73 }
74 }
75
76 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 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 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
110impl 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
124impl 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}