Skip to content

Commit 6f6985e

Browse files
committed
Border radius
1 parent d7b2e50 commit 6f6985e

File tree

12 files changed

+325
-40
lines changed

12 files changed

+325
-40
lines changed

src/lib.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,81 @@ mod tests {
334334
}"#
335335
});
336336
}
337+
338+
#[test]
339+
pub fn test_border_radius() {
340+
test(r#"
341+
.foo {
342+
border-radius: 10px 100px 10px 100px;
343+
}
344+
"#, indoc! {r#"
345+
.foo {
346+
border-radius: 10px 100px;
347+
}"#
348+
});
349+
350+
test(r#"
351+
.foo {
352+
border-radius: 10px 100px 10px 100px / 120px 120px;
353+
}
354+
"#, indoc! {r#"
355+
.foo {
356+
border-radius: 10px 100px / 120px;
357+
}"#
358+
});
359+
360+
test(r#"
361+
.foo {
362+
border-top-left-radius: 10px 120px;
363+
border-top-right-radius: 100px 120px;
364+
border-bottom-left-radius: 10px 120px;
365+
border-bottom-right-radius: 100px 120px;
366+
}
367+
"#, indoc! {r#"
368+
.foo {
369+
border-radius: 10px 100px / 120px;
370+
}"#
371+
});
372+
373+
test(r#"
374+
.foo {
375+
border-radius: 10px 100px 10px 100px / 120px 120px;
376+
border-start-start-radius: 10px;
377+
}
378+
"#, indoc! {r#"
379+
.foo {
380+
border-radius: 10px 100px / 120px;
381+
border-start-start-radius: 10px;
382+
}"#
383+
});
384+
385+
test(r#"
386+
.foo {
387+
border-start-start-radius: 10px;
388+
border-radius: 10px 100px 10px 100px / 120px 120px;
389+
}
390+
"#, indoc! {r#"
391+
.foo {
392+
border-radius: 10px 100px / 120px;
393+
}"#
394+
});
395+
396+
test(r#"
397+
.foo {
398+
border-top-left-radius: 10px 120px;
399+
border-top-right-radius: 100px 120px;
400+
border-start-start-radius: 10px;
401+
border-bottom-left-radius: 10px 120px;
402+
border-bottom-right-radius: 100px 120px;
403+
}
404+
"#, indoc! {r#"
405+
.foo {
406+
border-top-left-radius: 10px 120px;
407+
border-top-right-radius: 100px 120px;
408+
border-start-start-radius: 10px;
409+
border-bottom-left-radius: 10px 120px;
410+
border-bottom-right-radius: 100px 120px;
411+
}"#
412+
});
413+
}
337414
}

src/properties/mod.rs

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

33
use cssparser::*;
44
use custom::*;
5-
use crate::values::{image::*, length::*, border::*, border_image::*, rect::*, color::*};
6-
use super::values::traits::Parse;
5+
use crate::values::{image::*, length::*, border::*, border_image::*, border_radius::*, rect::*, color::*};
6+
use super::values::traits::{Parse, ToCss};
77

88
#[derive(Debug, Clone)]
99
pub enum Property {
@@ -72,18 +72,15 @@ pub enum Property {
7272
BorderInlineStartWidth(BorderSideWidth),
7373
BorderInlineEndWidth(BorderSideWidth),
7474

75-
// BorderBlock
76-
// BorderInline
77-
78-
// BorderTopLeftRadius
79-
// BorderTopRightRadius
80-
// BorderBottomLeftRadius
81-
// BorderBottomRightRadius
82-
// BorderStartStartRadius
83-
// BorderStartEndRadius
84-
// BorderEndStartRadius
85-
// BorderEndEndRadius
86-
// BorderRadius
75+
BorderTopLeftRadius(Size2D),
76+
BorderTopRightRadius(Size2D),
77+
BorderBottomLeftRadius(Size2D),
78+
BorderBottomRightRadius(Size2D),
79+
BorderStartStartRadius(Size2D),
80+
BorderStartEndRadius(Size2D),
81+
BorderEndStartRadius(Size2D),
82+
BorderEndEndRadius(Size2D),
83+
BorderRadius(BorderRadius),
8784

8885
/// https://www.w3.org/TR/css-backgrounds-3/#border-image-source
8986
BorderImageSource(Image),
@@ -220,6 +217,15 @@ impl Property {
220217
"border-image-width" => property!(BorderImageWidth, Rect),
221218
"border-image-slice" => property!(BorderImageSlice, BorderImageSlice),
222219
"border-image" => property!(BorderImage, BorderImage),
220+
"border-top-left-radius" => property!(BorderTopLeftRadius, Size2D),
221+
"border-top-right-radius" => property!(BorderTopRightRadius, Size2D),
222+
"border-bottom-left-radius" => property!(BorderBottomLeftRadius, Size2D),
223+
"border-bottom-right-radius" => property!(BorderBottomRightRadius, Size2D),
224+
"border-start-start-radius" => property!(BorderStartStartRadius, Size2D),
225+
"border-start-end-radius" => property!(BorderStartEndRadius, Size2D),
226+
"border-end-start-radius" => property!(BorderEndStartRadius, Size2D),
227+
"border-end-end-radius" => property!(BorderEndEndRadius, Size2D),
228+
"border-radius" => property!(BorderRadius, BorderRadius),
223229
_ => {}
224230
}
225231

@@ -326,6 +332,15 @@ impl Property {
326332
BorderImageWidth(val) => property!("border-image-width", val),
327333
BorderImageSlice(val) => property!("border-image-slice", val),
328334
BorderImage(val) => property!("border-image", val),
335+
BorderTopLeftRadius(val) => property!("border-top-left-radius", val),
336+
BorderTopRightRadius(val) => property!("border-top-right-radius", val),
337+
BorderBottomLeftRadius(val) => property!("border-bottom-left-radius", val),
338+
BorderBottomRightRadius(val) => property!("border-bottom-right-radius", val),
339+
BorderStartStartRadius(val) => property!("border-start-start-radius", val),
340+
BorderStartEndRadius(val) => property!("border-start-end-radius", val),
341+
BorderEndStartRadius(val) => property!("border-end-start-radius", val),
342+
BorderEndEndRadius(val) => property!("border-end-end-radius", val),
343+
BorderRadius(val) => property!("border-radius", val),
329344
Custom(custom) => {
330345
dest.write_str(custom.name.as_ref())?;
331346
dest.write_str(": ")?;

src/values/border.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use super::length::*;
22
use cssparser::*;
3-
use super::traits::Parse;
3+
use super::traits::{Parse, ToCss};
44
use super::color::CssColor;
55
use crate::properties::Property;
66
use super::rect::Rect;
7-
#[macro_use]
87
use super::macros::*;
98
use super::border_image::*;
9+
use super::border_radius::*;
1010

1111
#[derive(Debug, Clone, PartialEq)]
1212
pub enum BorderSideWidth {
@@ -194,7 +194,8 @@ pub struct BorderHandler {
194194
border_inline_end: BorderShorthand,
195195
category: BorderCategory,
196196
decls: Vec<Property>,
197-
border_image_handler: BorderImageHandler
197+
border_image_handler: BorderImageHandler,
198+
border_radius_handler: BorderRadiusHandler
198199
}
199200

200201
impl BorderHandler {
@@ -308,7 +309,7 @@ impl BorderHandler {
308309
self.border_image_handler.reset();
309310
}
310311
_ => {
311-
return self.border_image_handler.handle_property(property)
312+
return self.border_image_handler.handle_property(property) || self.border_radius_handler.handle_property(property)
312313
}
313314
}
314315

@@ -521,6 +522,7 @@ impl BorderHandler {
521522
pub fn finalize(&mut self) -> Vec<Property> {
522523
self.flush();
523524
self.decls.extend(self.border_image_handler.finalize());
525+
self.decls.extend(self.border_radius_handler.finalize());
524526
std::mem::take(&mut self.decls)
525527
}
526528
}

src/values/border_image.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::length::{*, NumberOrPercentage};
22
use cssparser::*;
3-
use super::traits::Parse;
3+
use super::traits::{Parse, ToCss};
44
use crate::properties::Property;
55
use super::rect::Rect;
66
use super::image::Image;
@@ -280,33 +280,39 @@ impl BorderImageHandler {
280280

281281
pub fn finalize(&mut self) -> Vec<Property> {
282282
let mut decls = vec![];
283-
if self.source.is_some() && self.slice.is_some() && self.width.is_some() && self.outset.is_some() && self.repeat.is_some() {
283+
let source = std::mem::take(&mut self.source);
284+
let slice = std::mem::take(&mut self.slice);
285+
let width = std::mem::take(&mut self.width);
286+
let outset = std::mem::take(&mut self.outset);
287+
let repeat = std::mem::take(&mut self.repeat);
288+
289+
if source.is_some() && slice.is_some() && width.is_some() && outset.is_some() && repeat.is_some() {
284290
decls.push(Property::BorderImage(BorderImage {
285-
source: self.source.clone().unwrap(),
286-
slice: self.slice.clone().unwrap(),
287-
width: self.width.clone().unwrap(),
288-
outset: self.outset.clone().unwrap(),
289-
repeat: self.repeat.clone().unwrap()
291+
source: source.unwrap(),
292+
slice: slice.unwrap(),
293+
width: width.unwrap(),
294+
outset: outset.unwrap(),
295+
repeat: repeat.unwrap()
290296
}))
291297
} else {
292-
if let Some(source) = &self.source {
293-
decls.push(Property::BorderImageSource(source.clone()))
298+
if let Some(source) = source {
299+
decls.push(Property::BorderImageSource(source))
294300
}
295301

296-
if let Some(slice) = &self.slice {
297-
decls.push(Property::BorderImageSlice(slice.clone()))
302+
if let Some(slice) = slice {
303+
decls.push(Property::BorderImageSlice(slice))
298304
}
299305

300-
if let Some(width) = &self.width {
301-
decls.push(Property::BorderImageWidth(width.clone()))
306+
if let Some(width) = width {
307+
decls.push(Property::BorderImageWidth(width))
302308
}
303309

304-
if let Some(outset) = &self.outset {
305-
decls.push(Property::BorderImageOutset(outset.clone()))
310+
if let Some(outset) = outset {
311+
decls.push(Property::BorderImageOutset(outset))
306312
}
307313

308-
if let Some(repeat) = &self.repeat {
309-
decls.push(Property::BorderImageRepeat(repeat.clone()))
314+
if let Some(repeat) = repeat {
315+
decls.push(Property::BorderImageRepeat(repeat))
310316
}
311317
}
312318

src/values/border_radius.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use super::length::*;
2+
use cssparser::*;
3+
use super::traits::{Parse, ToCss};
4+
use crate::properties::Property;
5+
use super::rect::Rect;
6+
7+
#[derive(Debug, Clone, PartialEq)]
8+
pub struct BorderRadius {
9+
top_left: Size2D,
10+
top_right: Size2D,
11+
bottom_left: Size2D,
12+
bottom_right: Size2D
13+
}
14+
15+
impl Parse for BorderRadius {
16+
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
17+
let widths: Rect<LengthPercentage> = Rect::parse(input)?;
18+
let heights = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
19+
Rect::parse(input)?
20+
} else {
21+
widths.clone()
22+
};
23+
24+
Ok(BorderRadius {
25+
top_left: Size2D::new(widths.0, heights.0),
26+
top_right: Size2D::new(widths.1, heights.1),
27+
bottom_left: Size2D::new(widths.2, heights.2),
28+
bottom_right: Size2D::new(widths.3, heights.3)
29+
})
30+
}
31+
}
32+
33+
impl ToCss for BorderRadius {
34+
fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
35+
let widths = Rect::new(&self.top_left.width, &self.top_right.width, &self.bottom_left.width, &self.bottom_right.width);
36+
let heights = Rect::new(&self.top_left.height, &self.top_right.height, &self.bottom_left.height, &self.bottom_right.height);
37+
38+
widths.to_css(dest)?;
39+
if widths != heights {
40+
dest.write_str(" / ")?;
41+
heights.to_css(dest)?;
42+
}
43+
44+
Ok(())
45+
}
46+
}
47+
48+
#[derive(Default, Debug)]
49+
pub struct BorderRadiusHandler {
50+
top_left: Option<Size2D>,
51+
top_right: Option<Size2D>,
52+
bottom_left: Option<Size2D>,
53+
bottom_right: Option<Size2D>,
54+
decls: Vec<Property>
55+
}
56+
57+
impl BorderRadiusHandler {
58+
pub fn handle_property(&mut self, property: &Property) -> bool {
59+
use Property::*;
60+
match property {
61+
BorderTopLeftRadius(val) => self.top_left = Some(val.clone()),
62+
BorderTopRightRadius(val) => self.top_right = Some(val.clone()),
63+
BorderBottomLeftRadius(val) => self.bottom_left = Some(val.clone()),
64+
BorderBottomRightRadius(val) => self.bottom_right = Some(val.clone()),
65+
BorderStartStartRadius(_) | BorderStartEndRadius(_) | BorderEndStartRadius(_) | BorderEndEndRadius(_) => {
66+
self.flush();
67+
self.decls.push(property.clone());
68+
}
69+
BorderRadius(val) => {
70+
self.decls.clear();
71+
self.top_left = Some(val.top_left.clone());
72+
self.top_right = Some(val.top_right.clone());
73+
self.bottom_left = Some(val.bottom_left.clone());
74+
self.bottom_right = Some(val.bottom_right.clone());
75+
}
76+
_ => return false
77+
}
78+
79+
true
80+
}
81+
82+
pub fn flush(&mut self) {
83+
let top_left = std::mem::take(&mut self.top_left);
84+
let top_right = std::mem::take(&mut self.top_right);
85+
let bottom_left = std::mem::take(&mut self.bottom_left);
86+
let bottom_right = std::mem::take(&mut self.bottom_right);
87+
88+
if top_left.is_some() && top_right.is_some() && bottom_left.is_some() && bottom_right.is_some() {
89+
self.decls.push(Property::BorderRadius(BorderRadius {
90+
top_left: top_left.unwrap(),
91+
top_right: top_right.unwrap(),
92+
bottom_left: bottom_left.unwrap(),
93+
bottom_right: bottom_right.unwrap(),
94+
}))
95+
} else {
96+
if let Some(val) = top_left {
97+
self.decls.push(Property::BorderTopLeftRadius(val))
98+
}
99+
100+
if let Some(val) = top_right {
101+
self.decls.push(Property::BorderTopRightRadius(val))
102+
}
103+
104+
if let Some(val) = bottom_left {
105+
self.decls.push(Property::BorderBottomLeftRadius(val))
106+
}
107+
108+
if let Some(val) = bottom_right {
109+
self.decls.push(Property::BorderBottomRightRadius(val))
110+
}
111+
}
112+
}
113+
114+
pub fn finalize(&mut self) -> Vec<Property> {
115+
self.flush();
116+
std::mem::take(&mut self.decls)
117+
}
118+
}

src/values/color.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use cssparser::*;
2-
use super::traits::Parse;
2+
use super::traits::{Parse, ToCss};
33

44
#[derive(Debug, Clone, PartialEq)]
55
pub struct CssColor(Color);

src/values/image.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use cssparser::*;
2-
use super::traits::Parse;
2+
use super::traits::{Parse, ToCss};
33

44
/// https://www.w3.org/TR/css-images-3/#typedef-image
55
#[derive(Debug, Clone, PartialEq)]
@@ -33,6 +33,7 @@ impl Parse for Image {
3333
impl ToCss for Image {
3434
fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
3535
use Image::*;
36+
use cssparser::ToCss;
3637
match self {
3738
None => dest.write_str("none"),
3839
Url(url) => {

0 commit comments

Comments
 (0)