Skip to content

Commit 674329c

Browse files
committed
Handle outline
1 parent 3d72ca2 commit 674329c

File tree

6 files changed

+182
-14
lines changed

6 files changed

+182
-14
lines changed

src/lib.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,42 @@ mod tests {
413413
});
414414
}
415415

416+
#[test]
417+
pub fn test_outline() {
418+
test(r#"
419+
.foo {
420+
outline-width: 2px;
421+
outline-style: solid;
422+
outline-color: blue;
423+
}
424+
"#, indoc! {r#"
425+
.foo {
426+
outline: 2px solid #00f;
427+
}"#
428+
});
429+
430+
test(r#"
431+
.foo {
432+
outline: 2px solid blue;
433+
}
434+
"#, indoc! {r#"
435+
.foo {
436+
outline: 2px solid #00f;
437+
}"#
438+
});
439+
440+
test(r#"
441+
.foo {
442+
outline: 2px solid red;
443+
outline-color: blue;
444+
}
445+
"#, indoc! {r#"
446+
.foo {
447+
outline: 2px solid #00f;
448+
}"#
449+
});
450+
}
451+
416452
#[test]
417453
pub fn test_margin() {
418454
test(r#"

src/parser.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,13 @@ impl ToCss for StyleRule {
379379
impl StyleRule {
380380
pub fn minify(&mut self) {
381381
use crate::values::border::*;
382-
use crate::properties::margin_padding::*;
382+
use crate::properties::{margin_padding::*, outline::*};
383383
use crate::properties::background::BackgroundHandler;
384384

385385
// TODO: somehow macro-ify this
386386
let mut background_handler = BackgroundHandler::default();
387387
let mut border_handler = BorderHandler::default();
388+
let mut outline_handler = OutlineHandler::default();
388389
let mut margin_handler = MarginHandler::default();
389390
let mut padding_handler = PaddingHandler::default();
390391
let mut scroll_margin_handler = MarginHandler::default();
@@ -394,6 +395,7 @@ impl StyleRule {
394395
for decl in self.declarations.iter() {
395396
if !background_handler.handle_property(decl) &&
396397
!border_handler.handle_property(decl) &&
398+
!outline_handler.handle_property(decl) &&
397399
!margin_handler.handle_property(decl) &&
398400
!padding_handler.handle_property(decl) &&
399401
!scroll_margin_handler.handle_property(decl) &&
@@ -405,6 +407,7 @@ impl StyleRule {
405407

406408
decls.extend(background_handler.finalize());
407409
decls.extend(border_handler.finalize());
410+
decls.extend(outline_handler.finalize());
408411
decls.extend(margin_handler.finalize());
409412
decls.extend(padding_handler.finalize());
410413
decls.extend(scroll_margin_handler.finalize());

src/properties/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod custom;
22
pub mod margin_padding;
33
pub mod background;
4+
pub mod outline;
45

56
use cssparser::*;
67
use custom::*;
78
use background::*;
9+
use outline::*;
810
use crate::values::{image::*, length::*, border::*, border_image::*, border_radius::*, rect::*, color::*};
911
use super::values::traits::{Parse, ToCss};
1012

@@ -122,6 +124,11 @@ pub enum Property {
122124
BorderInlineStart(Border),
123125
BorderInlineEnd(Border),
124126

127+
Outline(Outline),
128+
OutlineColor(CssColor),
129+
OutlineStyle(OutlineStyle),
130+
OutlineWidth(BorderSideWidth),
131+
125132
MarginTop(LengthPercentageOrAuto),
126133
MarginBottom(LengthPercentageOrAuto),
127134
MarginLeft(LengthPercentageOrAuto),
@@ -169,6 +176,9 @@ pub enum Property {
169176
ScrollPaddingBlock(Size2D<LengthPercentageOrAuto>),
170177
ScrollPaddingInline(Size2D<LengthPercentageOrAuto>),
171178
ScrollPadding(Rect<LengthPercentageOrAuto>),
179+
180+
// shorthands: transitions, animations, columns, font, font-variant, list-style
181+
// flex, grid, gap, place-items, place-self, inset
172182
}
173183

174184
impl Property {
@@ -279,6 +289,10 @@ impl Property {
279289
"border-end-start-radius" => property!(BorderEndStartRadius, Size2D),
280290
"border-end-end-radius" => property!(BorderEndEndRadius, Size2D),
281291
"border-radius" => property!(BorderRadius, BorderRadius),
292+
"outline" => property!(Outline, Outline),
293+
"outline-color" => property!(OutlineColor, CssColor),
294+
"outline-style" => property!(OutlineStyle, OutlineStyle),
295+
"outline-width" => property!(OutlineWidth, BorderSideWidth),
282296
"margin-left" => property!(MarginLeft, LengthPercentageOrAuto),
283297
"margin-right" => property!(MarginRight, LengthPercentageOrAuto),
284298
"margin-top" => property!(MarginTop, LengthPercentageOrAuto),
@@ -447,6 +461,10 @@ impl Property {
447461
BorderEndStartRadius(val) => property!("border-end-start-radius", val),
448462
BorderEndEndRadius(val) => property!("border-end-end-radius", val),
449463
BorderRadius(val) => property!("border-radius", val),
464+
Outline(val) => property!("outline", val),
465+
OutlineColor(val) => property!("outline-color", val),
466+
OutlineStyle(val) => property!("outline-style", val),
467+
OutlineWidth(val) => property!("outline-width", val),
450468
MarginLeft(val) => property!("margin-left", val),
451469
MarginRight(val) => property!("margin-right", val),
452470
MarginTop(val) => property!("margin-top", val),

src/properties/outline.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use cssparser::*;
2+
use crate::values::border::{BorderStyle, GenericBorder, BorderSideWidth};
3+
use crate::values::traits::{Parse, ToCss, PropertyHandler};
4+
use crate::values::color::CssColor;
5+
use super::Property;
6+
7+
#[derive(Debug, Clone, PartialEq)]
8+
pub enum OutlineStyle {
9+
Auto,
10+
BorderStyle(BorderStyle)
11+
}
12+
13+
impl Parse for OutlineStyle {
14+
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
15+
if let Ok(border_style) = input.try_parse(BorderStyle::parse) {
16+
return Ok(OutlineStyle::BorderStyle(border_style))
17+
}
18+
19+
input.expect_ident_matching("auto")?;
20+
Ok(OutlineStyle::Auto)
21+
}
22+
}
23+
24+
impl ToCss for OutlineStyle {
25+
fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
26+
match self {
27+
OutlineStyle::Auto => dest.write_str("auto"),
28+
OutlineStyle::BorderStyle(border_style) => border_style.to_css(dest)
29+
}
30+
}
31+
}
32+
33+
impl Default for OutlineStyle {
34+
fn default() -> OutlineStyle {
35+
OutlineStyle::BorderStyle(BorderStyle::None)
36+
}
37+
}
38+
39+
pub type Outline = GenericBorder<OutlineStyle>;
40+
41+
#[derive(Default, Debug)]
42+
pub struct OutlineHandler {
43+
pub width: Option<BorderSideWidth>,
44+
pub style: Option<OutlineStyle>,
45+
pub color: Option<CssColor>
46+
}
47+
48+
impl PropertyHandler for OutlineHandler {
49+
fn handle_property(&mut self, property: &Property) -> bool {
50+
use Property::*;
51+
52+
match property {
53+
OutlineColor(val) => self.color = Some(val.clone()),
54+
OutlineStyle(val) => self.style = Some(val.clone()),
55+
OutlineWidth(val) => self.width = Some(val.clone()),
56+
Outline(val) => {
57+
self.color = Some(val.color.clone());
58+
self.style = Some(val.style.clone());
59+
self.width = Some(val.width.clone());
60+
}
61+
_ => return false
62+
}
63+
64+
true
65+
}
66+
67+
fn finalize(&mut self) -> Vec<Property> {
68+
let mut decls = vec![];
69+
let width = std::mem::take(&mut self.width);
70+
let style = std::mem::take(&mut self.style);
71+
let color = std::mem::take(&mut self.color);
72+
if width.is_some() && style.is_some() && color.is_some() {
73+
decls.push(Property::Outline(Outline {
74+
width: width.unwrap(),
75+
style: style.unwrap(),
76+
color: color.unwrap()
77+
}))
78+
} else {
79+
if let Some(color) = color {
80+
decls.push(Property::OutlineColor(color))
81+
}
82+
83+
if let Some(style) = style {
84+
decls.push(Property::OutlineStyle(style))
85+
}
86+
87+
if let Some(width) = width {
88+
decls.push(Property::OutlineWidth(width))
89+
}
90+
}
91+
92+
decls
93+
}
94+
}

src/values/border.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ pub enum BorderSideWidth {
2020
Length(Length),
2121
}
2222

23+
impl Default for BorderSideWidth {
24+
fn default() -> BorderSideWidth {
25+
BorderSideWidth::Medium
26+
}
27+
}
28+
2329
impl Parse for BorderSideWidth {
2430
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
2531
if let Ok(length) = input.try_parse(|i| Length::parse(i)) {
@@ -60,24 +66,30 @@ enum_property!(BorderStyle,
6066
Double
6167
);
6268

69+
impl Default for BorderStyle {
70+
fn default() -> BorderStyle {
71+
BorderStyle::None
72+
}
73+
}
74+
6375
#[derive(Debug, Clone, PartialEq)]
64-
pub struct Border {
76+
pub struct GenericBorder<S> {
6577
pub width: BorderSideWidth,
66-
pub style: BorderStyle,
78+
pub style: S,
6779
pub color: CssColor
6880
}
6981

70-
impl Default for Border {
71-
fn default() -> Border {
72-
Border {
82+
impl<S: Default> Default for GenericBorder<S> {
83+
fn default() -> GenericBorder<S> {
84+
GenericBorder {
7385
width: BorderSideWidth::Medium,
74-
style: BorderStyle::None,
86+
style: S::default(),
7587
color: CssColor::current_color()
7688
}
7789
}
7890
}
7991

80-
impl Parse for Border {
92+
impl<S: Parse + Default> Parse for GenericBorder<S> {
8193
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ()>> {
8294
// Order doesn't matter...
8395
let mut color = None;
@@ -92,7 +104,7 @@ impl Parse for Border {
92104
}
93105
}
94106
if style.is_none() {
95-
if let Ok(value) = input.try_parse(BorderStyle::parse) {
107+
if let Ok(value) = input.try_parse(S::parse) {
96108
style = Some(value);
97109
any = true;
98110
continue
@@ -108,9 +120,9 @@ impl Parse for Border {
108120
break
109121
}
110122
if any {
111-
Ok(Border {
123+
Ok(GenericBorder {
112124
width: width.unwrap_or(BorderSideWidth::Medium),
113-
style: style.unwrap_or(BorderStyle::None),
125+
style: style.unwrap_or_default(),
114126
color: color.unwrap_or_else(|| CssColor::current_color())
115127
})
116128
} else {
@@ -119,13 +131,13 @@ impl Parse for Border {
119131
}
120132
}
121133

122-
impl ToCss for Border {
134+
impl<S: ToCss + Default + PartialEq> ToCss for GenericBorder<S> {
123135
fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write {
124-
if self.width != BorderSideWidth::Medium {
136+
if self.width != BorderSideWidth::default() {
125137
self.width.to_css(dest)?;
126138
dest.write_str(" ")?;
127139
}
128-
if self.style != BorderStyle::None {
140+
if self.style != S::default() {
129141
self.style.to_css(dest)?;
130142
dest.write_str(" ")?;
131143
}
@@ -136,6 +148,7 @@ impl ToCss for Border {
136148
}
137149
}
138150

151+
pub type Border = GenericBorder<BorderStyle>;
139152

140153
#[derive(Default, Debug, PartialEq)]
141154
pub struct BorderShorthand {

test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ css.transform({
1212
background-position-y: top 20px, 15px;
1313
background-size: 50px 50px, auto;
1414
background-repeat: repeat no-repeat, no-repeat;
15+
// outline: 2px auto red;
16+
outline-color: blue;
17+
outline-width: 2px;
18+
outline-style: solid;
1519
// background: url("chess.png") 40% / 10em gray, url(img.png);
1620
color: blue;
1721
width: 250px;

0 commit comments

Comments
 (0)