Skip to content

Commit ff88d98

Browse files
committed
Parse lengths
1 parent 382d387 commit ff88d98

File tree

4 files changed

+369
-2
lines changed

4 files changed

+369
-2
lines changed

src/properties/mod.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,36 @@ mod custom;
22

33
use cssparser::*;
44
use custom::*;
5-
use crate::values::{image::*};
5+
use crate::values::{image::*, length::*};
66

77
#[derive(Debug)]
88
pub enum Property {
99
BackgroundColor(Color),
1010
BackgroundImage(Vec<Image>),
1111
Color(Color),
12-
Custom(CustomProperty)
12+
Custom(CustomProperty),
13+
14+
Width(Size),
15+
Height(Size),
16+
MinWidth(MinMaxSize),
17+
MinHeight(MinMaxSize),
18+
MaxWidth(MinMaxSize),
19+
MaxHeight(MinMaxSize),
20+
BlockSize(Size),
21+
InlineSize(Size),
22+
MinBlockSize(MinMaxSize),
23+
MinInlineSize(MinMaxSize),
24+
MaxBlockSize(MinMaxSize),
25+
MaxInlineSize(MinMaxSize),
26+
27+
Top(LengthPercentageOrAuto),
28+
Bottom(LengthPercentageOrAuto),
29+
Left(LengthPercentageOrAuto),
30+
Right(LengthPercentageOrAuto),
31+
InsetBlockStart(LengthPercentageOrAuto),
32+
InsetBlockEnd(LengthPercentageOrAuto),
33+
InsetInlineStart(LengthPercentageOrAuto),
34+
InsetInlineEnd(LengthPercentageOrAuto)
1335
}
1436

1537
impl Property {
@@ -32,6 +54,26 @@ impl Property {
3254
"background-color" => property!(BackgroundColor, Color),
3355
"background-image" => property!(BackgroundImage, Image, true),
3456
"color" => property!(Color, Color),
57+
"width" => property!(Width, Size),
58+
"height" => property!(Height, Size),
59+
"min-width" => property!(MinWidth, MinMaxSize),
60+
"min-height" => property!(MinHeight, MinMaxSize),
61+
"max-width" => property!(MaxWidth, MinMaxSize),
62+
"max-height" => property!(MaxHeight, MinMaxSize),
63+
"block-size" => property!(BlockSize, Size),
64+
"inline-size" => property!(InlineSize, Size),
65+
"min-block-size" => property!(MinBlockSize, MinMaxSize),
66+
"min-inline-size" => property!(MinInlineSize, MinMaxSize),
67+
"max-block-size" => property!(MaxBlockSize, MinMaxSize),
68+
"max-inline-size" => property!(MaxInlineSize, MinMaxSize),
69+
"top" => property!(Top, LengthPercentageOrAuto),
70+
"bottom" => property!(Bottom, LengthPercentageOrAuto),
71+
"left" => property!(Left, LengthPercentageOrAuto),
72+
"right" => property!(Right, LengthPercentageOrAuto),
73+
"inset-block-start" => property!(InsetBlockStart, LengthPercentageOrAuto),
74+
"inset-block-end" => property!(InsetBlockEnd, LengthPercentageOrAuto),
75+
"inset-inline-start" => property!(InsetInlineStart, LengthPercentageOrAuto),
76+
"inset-inline-end" => property!(InsetInlineEnd, LengthPercentageOrAuto),
3577
_ => {}
3678
}
3779

@@ -68,6 +110,26 @@ impl Property {
68110
BackgroundColor(color) => property!("background-color", color),
69111
BackgroundImage(image) => property!("background-image", image, true),
70112
Color(color) => property!("color", color),
113+
Width(val) => property!("width", val),
114+
Height(val) => property!("height", val),
115+
MinWidth(val) => property!("min-width", val),
116+
MinHeight(val) => property!("min-height", val),
117+
MaxWidth(val) => property!("max-width", val),
118+
MaxHeight(val) => property!("max-height", val),
119+
BlockSize(val) => property!("block-size", val),
120+
InlineSize(val) => property!("inline-size", val),
121+
MinBlockSize(val) => property!("min-block-size", val),
122+
MinInlineSize(val) => property!("min-inline-size", val),
123+
MaxBlockSize(val) => property!("max-block-size", val),
124+
MaxInlineSize(val) => property!("max-inline-size", val),
125+
Top(val) => property!("top", val),
126+
Bottom(val) => property!("bottom", val),
127+
Left(val) => property!("left", val),
128+
Right(val) => property!("right", val),
129+
InsetBlockStart(val) => property!("inset-block-start", val),
130+
InsetBlockEnd(val) => property!("inset-block-end", val),
131+
InsetInlineStart(val) => property!("inset-inline-start", val),
132+
InsetInlineEnd(val) => property!("inset-inline-end", val),
71133
Custom(custom) => {
72134
dest.write_str(custom.name.as_ref())?;
73135
dest.write_str(": ")?;

src/values/length.rs

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
use cssparser::*;
2+
3+
/// https://drafts.csswg.org/css-sizing-3/#specifying-sizes
4+
5+
/// https://drafts.csswg.org/css-sizing-3/#preferred-size-properties
6+
#[derive(Debug)]
7+
pub enum Size {
8+
Auto,
9+
LengthPercentage(LengthPercentage),
10+
MinContent,
11+
MaxContent,
12+
FitContent(LengthPercentage)
13+
}
14+
15+
impl Size {
16+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
17+
if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
18+
return Ok(Size::Auto);
19+
}
20+
21+
if input.try_parse(|i| i.expect_ident_matching("min-content")).is_ok() {
22+
return Ok(Size::MinContent);
23+
}
24+
25+
if input.try_parse(|i| i.expect_ident_matching("max-content")).is_ok() {
26+
return Ok(Size::MaxContent);
27+
}
28+
29+
if let Ok(l) = input.try_parse(|input| LengthPercentage::parse(input)) {
30+
return Ok(Size::LengthPercentage(l))
31+
}
32+
33+
if let Ok(l) = parse_fit_content(input) {
34+
return Ok(Size::FitContent(l))
35+
}
36+
37+
Err(input.new_error_for_next_token())
38+
}
39+
40+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
41+
use Size::*;
42+
match self {
43+
Auto => dest.write_str("auto"),
44+
MinContent => dest.write_str("min-content"),
45+
MaxContent => dest.write_str("max-content"),
46+
FitContent(l) => {
47+
dest.write_str("fit-content(")?;
48+
l.to_css(dest)?;
49+
dest.write_str(")")
50+
}
51+
LengthPercentage(l) => l.to_css(dest),
52+
_ => Ok(())
53+
}
54+
}
55+
}
56+
57+
/// https://drafts.csswg.org/css-sizing-3/#min-size-properties
58+
/// https://drafts.csswg.org/css-sizing-3/#max-size-properties
59+
#[derive(Debug)]
60+
pub enum MinMaxSize {
61+
None,
62+
LengthPercentage(LengthPercentage),
63+
MinContent,
64+
MaxContent,
65+
FitContent(LengthPercentage)
66+
}
67+
68+
impl MinMaxSize {
69+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
70+
if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
71+
return Ok(MinMaxSize::None);
72+
}
73+
74+
if input.try_parse(|i| i.expect_ident_matching("min-content")).is_ok() {
75+
return Ok(MinMaxSize::MinContent);
76+
}
77+
78+
if input.try_parse(|i| i.expect_ident_matching("max-content")).is_ok() {
79+
return Ok(MinMaxSize::MaxContent);
80+
}
81+
82+
if let Ok(percent) = input.try_parse(|input| LengthPercentage::parse(input)) {
83+
return Ok(MinMaxSize::LengthPercentage(percent))
84+
}
85+
86+
if let Ok(l) = parse_fit_content(input) {
87+
return Ok(MinMaxSize::FitContent(l))
88+
}
89+
90+
Err(input.new_error_for_next_token())
91+
}
92+
93+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
94+
use MinMaxSize::*;
95+
match self {
96+
None => dest.write_str("none"),
97+
MinContent => dest.write_str("min-content"),
98+
MaxContent => dest.write_str("max-content"),
99+
FitContent(l) => {
100+
dest.write_str("fit-content(")?;
101+
l.to_css(dest)?;
102+
dest.write_str(")")
103+
}
104+
LengthPercentage(l) => l.to_css(dest),
105+
_ => Ok(())
106+
}
107+
}
108+
}
109+
110+
/// https://drafts.csswg.org/css-values-4/#typedef-length-percentage
111+
#[derive(Debug)]
112+
pub enum LengthPercentage {
113+
Length(Length),
114+
Percentage(Percentage),
115+
// Calc()
116+
}
117+
118+
impl LengthPercentage {
119+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
120+
if let Ok(length) = input.try_parse(|input| Length::parse(input)) {
121+
return Ok(LengthPercentage::Length(length))
122+
}
123+
124+
if let Ok(percent) = input.try_parse(|input| Percentage::parse(input)) {
125+
return Ok(LengthPercentage::Percentage(percent))
126+
}
127+
128+
Err(input.new_error_for_next_token())
129+
}
130+
131+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
132+
match self {
133+
LengthPercentage::Length(length) => length.to_css(dest),
134+
LengthPercentage::Percentage(percent) => percent.to_css(dest)
135+
}
136+
}
137+
}
138+
139+
/// `<length-percentage> | auto`
140+
#[derive(Debug)]
141+
pub enum LengthPercentageOrAuto {
142+
Auto,
143+
LengthPercentage(LengthPercentage)
144+
}
145+
146+
impl LengthPercentageOrAuto {
147+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
148+
if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
149+
return Ok(LengthPercentageOrAuto::Auto);
150+
}
151+
152+
if let Ok(percent) = input.try_parse(|input| LengthPercentage::parse(input)) {
153+
return Ok(LengthPercentageOrAuto::LengthPercentage(percent))
154+
}
155+
156+
Err(input.new_error_for_next_token())
157+
}
158+
159+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
160+
use LengthPercentageOrAuto::*;
161+
match self {
162+
Auto => dest.write_str("auto"),
163+
LengthPercentage(l) => l.to_css(dest),
164+
_ => Ok(())
165+
}
166+
}
167+
}
168+
169+
#[derive(Debug)]
170+
pub enum Unit {
171+
Px,
172+
In,
173+
Cm,
174+
Mm,
175+
Q,
176+
Pt,
177+
Pc,
178+
Em,
179+
Ex,
180+
Ch,
181+
Rem,
182+
Vw,
183+
Vh,
184+
Vmin,
185+
Vmax,
186+
}
187+
188+
impl Unit {
189+
pub fn parse<'i, 't>(unit: &str) -> Result<Self, ()> {
190+
use Unit::*;
191+
Ok(match_ignore_ascii_case! { unit,
192+
"px" => Px,
193+
"in" => In,
194+
"cm" => Cm,
195+
"mm" => Mm,
196+
"q" => Q,
197+
"pt" => Pt,
198+
"pc" => Pc,
199+
"em" => Em,
200+
"ex" => Ex,
201+
"ch" => Ch,
202+
"rem" => Rem,
203+
"vw" => Vw,
204+
"vh" => Vh,
205+
"vmin" => Vmin,
206+
"vmax" => Vmax,
207+
_ => return Err(()),
208+
})
209+
}
210+
211+
pub fn as_str(&self) -> &str {
212+
use Unit::*;
213+
match self {
214+
Px => "px",
215+
In => "in",
216+
Cm => "cm",
217+
Mm => "mm",
218+
Q => "q",
219+
Pt => "pt",
220+
Pc => "pc",
221+
Em => "em",
222+
Ex => "ex",
223+
Ch => "ch",
224+
Rem => "rem",
225+
Vw => "vw",
226+
Vh => "vh",
227+
Vmin => "vmin",
228+
Vmax => "vmax"
229+
}
230+
}
231+
}
232+
233+
/// https://drafts.csswg.org/css-values-4/#lengths
234+
#[derive(Debug)]
235+
pub struct Length {
236+
value: f32,
237+
unit: Unit
238+
}
239+
240+
impl Length {
241+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
242+
let location = input.current_source_location();
243+
let token = input.next()?;
244+
match *token {
245+
Token::Dimension { value, ref unit, .. } => {
246+
Unit::parse(unit)
247+
.map(|unit| Length {
248+
value,
249+
unit
250+
})
251+
.map_err(|()| location.new_unexpected_token_error(token.clone()))
252+
},
253+
Token::Number { value, .. } => {
254+
// TODO: quirks mode only?
255+
Ok(Length {
256+
value,
257+
unit: Unit::Px
258+
})
259+
}
260+
ref token => return Err(location.new_unexpected_token_error(token.clone())),
261+
}
262+
}
263+
264+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
265+
let token = Token::Dimension {
266+
has_sign: false,
267+
value: self.value,
268+
int_value: None,
269+
unit: CowRcStr::from(self.unit.as_str())
270+
};
271+
token.to_css(dest)
272+
}
273+
}
274+
275+
/// https://drafts.csswg.org/css-values-4/#percentages
276+
#[derive(Debug)]
277+
pub struct Percentage(f32);
278+
279+
impl Percentage {
280+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
281+
let percent = input.expect_percentage()?;
282+
Ok(Percentage(percent))
283+
}
284+
285+
pub fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
286+
let percent = Token::Percentage {
287+
has_sign: false,
288+
unit_value: self.0,
289+
int_value: None
290+
};
291+
percent.to_css(dest)
292+
}
293+
}
294+
295+
fn parse_fit_content<'i, 't>(input: &mut Parser<'i, 't>) -> Result<LengthPercentage, ParseError<'i, ()>> {
296+
input.expect_function_matching("fit-content")?;
297+
input.parse_nested_block(|input| LengthPercentage::parse(input))
298+
}

src/values/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod image;
2+
pub mod length;

0 commit comments

Comments
 (0)