use cssparser::Parser;
use crate::style::Declaration;
use crate::style::properties::{BorderStyle, Color, Length};
use super::box_model::expand_shorthand_4;
use super::keywords::parse_border_style_value;
use super::values::{parse_color, parse_length};
#[derive(Clone, Copy)]
pub(crate) enum BorderSide {
Top,
Right,
Bottom,
Left,
}
impl BorderSide {
pub(crate) fn make_declarations(
self,
width: Option<Length>,
style: Option<BorderStyle>,
color: Option<Color>,
) -> Vec<Declaration> {
let mut decls = Vec::with_capacity(3);
if let Some(w) = width {
decls.push(match self {
BorderSide::Top => Declaration::BorderTopWidth(w),
BorderSide::Right => Declaration::BorderRightWidth(w),
BorderSide::Bottom => Declaration::BorderBottomWidth(w),
BorderSide::Left => Declaration::BorderLeftWidth(w),
});
}
if let Some(s) = style {
decls.push(match self {
BorderSide::Top => Declaration::BorderTopStyle(s),
BorderSide::Right => Declaration::BorderRightStyle(s),
BorderSide::Bottom => Declaration::BorderBottomStyle(s),
BorderSide::Left => Declaration::BorderLeftStyle(s),
});
}
if let Some(c) = color {
decls.push(match self {
BorderSide::Top => Declaration::BorderTopColor(c),
BorderSide::Right => Declaration::BorderRightColor(c),
BorderSide::Bottom => Declaration::BorderBottomColor(c),
BorderSide::Left => Declaration::BorderLeftColor(c),
});
}
decls
}
}
pub(crate) fn parse_border_width_value(input: &mut Parser<'_, '_>) -> Option<Length> {
if let Ok(token) = input.try_parse(|i| i.expect_ident_cloned()) {
let width = match token.as_ref() {
"thin" => Length::Px(1.0),
"medium" => Length::Px(3.0),
"thick" => Length::Px(5.0),
_ => return None,
};
return Some(width);
}
parse_length(input)
}
pub(crate) fn parse_border_values(
input: &mut Parser<'_, '_>,
) -> (Option<Length>, Option<BorderStyle>, Option<Color>) {
let mut width: Option<Length> = None;
let mut style: Option<BorderStyle> = None;
let mut color: Option<Color> = None;
for _ in 0..3 {
if style.is_none()
&& let Ok(s) = input.try_parse(|i| {
parse_border_style_value(i).ok_or_else(|| i.new_custom_error::<_, ()>(()))
})
{
style = Some(s);
continue;
}
if color.is_none()
&& let Ok(c) =
input.try_parse(|i| parse_color(i).ok_or_else(|| i.new_custom_error::<_, ()>(())))
{
color = Some(c);
continue;
}
if width.is_none()
&& let Ok(w) = input.try_parse(|i| {
parse_border_width_value(i).ok_or_else(|| i.new_custom_error::<_, ()>(()))
})
{
width = Some(w);
continue;
}
break;
}
(width, style, color)
}
pub(crate) fn parse_border_side_shorthand(
input: &mut Parser<'_, '_>,
side: BorderSide,
) -> Vec<Declaration> {
let (width, style, color) = parse_border_values(input);
if width.is_none() && style.is_none() && color.is_none() {
return vec![];
}
side.make_declarations(width, style, color)
}
pub(crate) fn parse_border_shorthand(input: &mut Parser<'_, '_>) -> Vec<Declaration> {
let (width, style, color) = parse_border_values(input);
if width.is_none() && style.is_none() && color.is_none() {
return vec![];
}
let mut decls = Vec::with_capacity(12);
if let Some(w) = width {
decls.push(Declaration::BorderTopWidth(w));
decls.push(Declaration::BorderRightWidth(w));
decls.push(Declaration::BorderBottomWidth(w));
decls.push(Declaration::BorderLeftWidth(w));
}
if let Some(s) = style {
decls.push(Declaration::BorderTopStyle(s));
decls.push(Declaration::BorderRightStyle(s));
decls.push(Declaration::BorderBottomStyle(s));
decls.push(Declaration::BorderLeftStyle(s));
}
if let Some(c) = color {
decls.push(Declaration::BorderTopColor(c));
decls.push(Declaration::BorderRightColor(c));
decls.push(Declaration::BorderBottomColor(c));
decls.push(Declaration::BorderLeftColor(c));
}
decls
}
pub(crate) fn parse_border_style_shorthand_values(
input: &mut Parser<'_, '_>,
) -> Option<(BorderStyle, BorderStyle, BorderStyle, BorderStyle)> {
let mut values = Vec::with_capacity(4);
while values.len() < 4 {
if let Some(style) = parse_border_style_value(input) {
values.push(style);
} else {
break;
}
}
expand_shorthand_4(values)
}
pub(crate) fn parse_color_shorthand_values(
input: &mut Parser<'_, '_>,
) -> Option<(Color, Color, Color, Color)> {
let mut values = Vec::with_capacity(4);
while values.len() < 4 {
if let Some(color) = parse_color(input) {
values.push(color);
} else {
break;
}
}
expand_shorthand_4(values)
}