Skip to content

Commit

Permalink
Improve border shorthand minification
Browse files Browse the repository at this point in the history
Fixes #35
  • Loading branch information
devongovett committed Jan 30, 2022
1 parent 718efba commit 46cca00
Show file tree
Hide file tree
Showing 2 changed files with 262 additions and 41 deletions.
154 changes: 154 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,160 @@ mod tests {
"#
});

test(r#"
.foo {
border: 1px solid black;
border-width: 1px 1px 0 0;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-width: 1px 1px 0 0;
}
"#});

test(r#"
.foo {
border-top: 1px solid black;
border-bottom: 1px solid black;
border-left: 2px solid black;
border-right: 2px solid black;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-width: 1px 2px;
}
"#});

test(r#"
.foo {
border-top: 1px solid black;
border-bottom: 1px solid black;
border-left: 2px solid black;
border-right: 1px solid black;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-left-width: 2px;
}
"#});

test(r#"
.foo {
border-top: 1px solid black;
border-bottom: 1px solid black;
border-left: 1px solid red;
border-right: 1px solid red;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-color: #000 red;
}
"#});

test(r#"
.foo {
border-block-start: 1px solid black;
border-block-end: 1px solid black;
border-inline-start: 1px solid red;
border-inline-end: 1px solid red;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-inline-color: red;
}
"#});

test(r#"
.foo {
border-block-start: 1px solid black;
border-block-end: 1px solid black;
border-inline-start: 2px solid black;
border-inline-end: 2px solid black;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-inline-width: 2px;
}
"#});

test(r#"
.foo {
border-block-start: 1px solid black;
border-block-end: 1px solid black;
border-inline-start: 2px solid red;
border-inline-end: 2px solid red;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-inline: 2px solid red;
}
"#});

test(r#"
.foo {
border-block-start: 1px solid black;
border-block-end: 1px solid black;
border-inline-start: 2px solid red;
border-inline-end: 3px solid red;
}
"#, indoc! {r#"
.foo {
border: 1px solid #000;
border-inline-start: 2px solid red;
border-inline-end: 3px solid red;
}
"#});

test(r#"
.foo {
border-block-start: 2px solid black;
border-block-end: 1px solid black;
border-inline-start: 2px solid red;
border-inline-end: 2px solid red;
}
"#, indoc! {r#"
.foo {
border: 2px solid red;
border-block-start-color: #000;
border-block-end: 1px solid #000;
}
"#});

test(r#"
.foo {
border-block-start: 2px solid red;
border-block-end: 1px solid red;
border-inline-start: 2px solid red;
border-inline-end: 2px solid red;
}
"#, indoc! {r#"
.foo {
border: 2px solid red;
border-block-end-width: 1px;
}
"#});

test(r#"
.foo {
border-block-start: 2px solid red;
border-block-end: 2px solid red;
border-inline-start: 2px solid red;
border-inline-end: 1px solid red;
}
"#, indoc! {r#"
.foo {
border: 2px solid red;
border-inline-end-width: 1px;
}
"#});

prefix_test(r#"
.foo {
border-block: 2px solid red;
Expand Down
149 changes: 108 additions & 41 deletions src/properties/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,34 @@ impl<'i> BorderHandler<'i> {
$inline_end: expr,
$is_logical: expr
) => {
macro_rules! shorthand {
($prop: ident, $key: ident) => {{
let has_prop = $block_start.$key.is_some() && $block_end.$key.is_some() && $inline_start.$key.is_some() && $inline_end.$key.is_some();
if has_prop {
if !$is_logical || ($block_start.$key == $block_end.$key && $block_end.$key == $inline_start.$key && $inline_start.$key == $inline_end.$key) {
let rect = Rect::new(
std::mem::take(&mut $block_start.$key).unwrap(),
std::mem::take(&mut $inline_end.$key).unwrap(),
std::mem::take(&mut $block_end.$key).unwrap(),
std::mem::take(&mut $inline_start.$key).unwrap()
);
prop!($prop => rect);
}
}
}};
}

macro_rules! logical_shorthand {
($prop: ident, $key: ident, $start: expr, $end: expr) => {{
let has_prop = $start.$key.is_some() && $start.$key == $end.$key;
if has_prop {
prop!($prop => std::mem::take(&mut $start.$key).unwrap());
$end.$key = None;
}
has_prop
}};
}

if $block_start.is_valid() && $block_end.is_valid() && $inline_start.is_valid() && $inline_end.is_valid() {
let top_eq_bottom = $block_start == $block_end;
let left_eq_right = $inline_start == $inline_end;
Expand All @@ -608,6 +636,34 @@ impl<'i> BorderHandler<'i> {
let bottom_eq_left = $block_end == $inline_start;
let bottom_eq_right = $block_end == $inline_end;

macro_rules! is_eq {
($key: ident) => {
$block_start.$key == $block_end.$key &&
$inline_start.$key == $inline_end.$key &&
$inline_start.$key == $block_start.$key
};
}

macro_rules! prop_diff {
($border: expr, $fallback: expr, $border_fallback: literal) => {
if !$is_logical && is_eq!(color) && is_eq!(style) {
dest.push(Property::Border($border.to_border()));
shorthand!(BorderWidth, width);
} else if !$is_logical && is_eq!(width) && is_eq!(style) {
dest.push(Property::Border($border.to_border()));
shorthand!(BorderColor, color);
} else if !$is_logical && is_eq!(width) && is_eq!(color) {
dest.push(Property::Border($border.to_border()));
shorthand!(BorderStyle, style);
} else {
if $border_fallback {
dest.push(Property::Border($border.to_border()));
}
$fallback
}
};
}

macro_rules! side_diff {
($border: expr, $other: expr, $prop: ident, $width: ident, $style: ident, $color: ident) => {
let eq_width = $border.width == $other.width;
Expand Down Expand Up @@ -643,52 +699,63 @@ impl<'i> BorderHandler<'i> {
dest.push(Property::Border($inline_start.to_border()));
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
} else if top_eq_bottom {
dest.push(Property::Border($block_start.to_border()));
side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
} else if left_eq_right {
dest.push(Property::Border($inline_start.to_border()));
side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
} else if bottom_eq_right {
dest.push(Property::Border($block_end.to_border()));
side_diff!($block_end, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
side_diff!($block_end, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
} else {
prop!($block_start_prop => $block_start.to_border());
prop!($block_end_prop => $block_end.to_border());
prop!($inline_start_prop => $inline_start.to_border());
prop!($inline_end_prop => $inline_end.to_border());
}
} else {
macro_rules! shorthand {
($prop: ident, $key: ident) => {{
let has_prop = $block_start.$key.is_some() && $block_end.$key.is_some() && $inline_start.$key.is_some() && $inline_end.$key.is_some();
if has_prop {
if !$is_logical || ($block_start.$key == $block_end.$key && $block_end.$key == $inline_start.$key && $inline_start.$key == $inline_end.$key) {
let rect = Rect::new(
std::mem::take(&mut $block_start.$key).unwrap(),
std::mem::take(&mut $inline_end.$key).unwrap(),
std::mem::take(&mut $block_end.$key).unwrap(),
std::mem::take(&mut $inline_start.$key).unwrap()
);
prop!($prop => rect);
prop_diff!($block_start, {
// Try to use border-inline shorthands for the opposide direction if possible.
let mut handled = false;
if $is_logical {
let mut diff = 0;
if $inline_start.width != $block_start.width || $inline_end.width != $block_start.width {
diff += 1;
}
if $inline_start.style != $block_start.style || $inline_end.style != $block_start.style {
diff += 1;
}
if $inline_start.color != $block_start.color || $inline_end.color != $block_start.color {
diff += 1;
}

if diff == 1 {
if $inline_start.width != $block_start.width && $inline_start.width == $inline_end.width {
prop!(BorderInlineWidth => $inline_start.width.clone().unwrap());
handled = true;
} else if $inline_start.style != $block_start.style && $inline_start.style == $inline_end.style {
prop!(BorderInlineStyle => $inline_start.style.clone().unwrap());
handled = true;
} else if $inline_start.color != $block_start.color && $inline_start.color == $inline_end.color {
prop!(BorderInlineColor => $inline_start.color.clone().unwrap());
handled = true;
}
} else if diff > 1 && $inline_start.width == $inline_end.width && $inline_start.style == $inline_end.style && $inline_start.color == $inline_end.color {
prop!(BorderInline => $inline_start.to_border());
handled = true;
}
}
}};
}

macro_rules! logical_shorthand {
($prop: ident, $key: ident, $start: expr, $end: expr) => {{
let has_prop = $start.$key.is_some() && $start.$key == $end.$key;
if has_prop {
prop!($prop => std::mem::take(&mut $start.$key).unwrap());
$end.$key = None;
if !handled {
side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
}
has_prop
}};
}, true);
} else if left_eq_right {
prop_diff!($inline_start, {
// We know already that top != bottom, so no need to try to use border-block.
side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
}, true);
} else if bottom_eq_right {
prop_diff!($block_end, {
side_diff!($block_end, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
side_diff!($block_end, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
}, true);
} else {
prop_diff!($block_start, {
prop!($block_start_prop => $block_start.to_border());
prop!($block_end_prop => $block_end.to_border());
prop!($inline_start_prop => $inline_start.to_border());
prop!($inline_end_prop => $inline_end.to_border());
}, false);
}

} else {
shorthand!(BorderStyle, style);
shorthand!(BorderWidth, width);
shorthand!(BorderColor, color);
Expand Down

0 comments on commit 46cca00

Please sign in to comment.