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