Skip to content

Commit 474eefe

Browse files
Handle additional cases of calc compressions with nested calc functions, shapes, and subtracting negative values (#264)
1 parent b5898c2 commit 474eefe

File tree

9 files changed

+113
-21
lines changed

9 files changed

+113
-21
lines changed

src/main/java/org/primefaces/extensions/optimizerplugin/optimizer/CssCompressor.java

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -545,26 +545,7 @@ public void compress(Writer out, int linebreakpos) throws IOException {
545545
css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i));
546546
}
547547

548-
// Add spaces back in between operators for css calc function
549-
// https://developer.mozilla.org/en-US/docs/Web/CSS/calc
550-
// Added by Eric Arnol-Martin (earnolmartin@gmail.com)
551-
sb = new StringBuilder();
552-
p = Pattern.compile("calc\\([^;}]*\\)");
553-
m = p.matcher(css);
554-
while (m.find()) {
555-
String s = m.group();
556-
s = s.replaceAll("\\s+", "");
557-
s = s.replaceAll("(?<=[-|%)pxemrvhw\\d])\\+", " + ");
558-
s = s.replaceAll("(?<=[-|%)pxemrvhw\\d])-", " - ");
559-
s = s.replaceAll("(?<=[-|%)pxemrvhw\\d])\\*", " * ");
560-
s = s.replaceAll("(?<=[-|%)pxemrvhw\\d])/", " / ");
561-
s = s.replaceAll("(var\\(-\\s-\\s)", "var(--");
562-
s = s.replaceAll("\\)(var\\(--)", ") var(--"); // #168
563-
564-
m.appendReplacement(sb, s);
565-
}
566-
m.appendTail(sb);
567-
css = sb.toString();
548+
css = performCalcCompressions(css);
568549

569550
// #240 add spaces after parens
570551
css = css.replaceAll("\\)(?=[a-zA-Z0-9])", ") ") // Add space after ')' if followed by letter/digit
@@ -653,4 +634,56 @@ public static String normalizeSpace(final String str) {
653634
}
654635
return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
655636
}
637+
638+
private static String performCalcCompressions(String css) {
639+
StringBuilder compressed = new StringBuilder();
640+
while (!css.isBlank())
641+
css = seekNextCalcCompression(compressed, css);
642+
return compressed.toString();
643+
}
644+
645+
private static String seekNextCalcCompression(StringBuilder compressed, String css) {
646+
int calcStartIndex = css.indexOf("calc(");
647+
if (calcStartIndex >= 0)
648+
return compressCalcFormAt(compressed, css, calcStartIndex);
649+
compressed.append(css);
650+
return "";
651+
}
652+
653+
private static String compressCalcFormAt(StringBuilder compressed, String css, int calcStartIndex) {
654+
compressed.append(css, 0, calcStartIndex);
655+
css = css.substring(calcStartIndex);
656+
String calcForm = readNextCalcForm(css);
657+
compressed.append(compressCalcForm(calcForm));
658+
return css.substring(calcForm.length());
659+
}
660+
661+
private static String readNextCalcForm(String css) {
662+
// Assumes "calc(" is at the head of the string
663+
int cursor = 4;
664+
int depth = 1;
665+
while (++cursor < css.length()) {
666+
char next = css.charAt(cursor);
667+
if (next == '(') depth++;
668+
else if (next == ')') depth--;
669+
if (depth == 0) break;
670+
}
671+
cursor = Integer.min(cursor, css.length() - 1);
672+
return css.substring(0, cursor + 1);
673+
}
674+
675+
// Add spaces back in between operators for css calc function
676+
// https://developer.mozilla.org/en-US/docs/Web/CSS/calc
677+
// Added by Eric Arnol-Martin (earnolmartin@gmail.com)
678+
private static String compressCalcForm(String calcForm) {
679+
return calcForm
680+
.replaceAll("\\s+", "")
681+
.replaceAll("(?<=[-|%)pxemrvhw\\d])--", " - -")
682+
.replaceAll("(?<=[-|%)pxemrvhw\\d])\\+", " + ")
683+
.replaceAll("(?<=[-|%)pxemrvhw\\d])-", " - ")
684+
.replaceAll("(?<=[-|%)pxemrvhw\\d])\\*", " * ")
685+
.replaceAll("(?<=[-|%)pxemrvhw\\d])/", " / ")
686+
.replaceAll("(var\\(-\\s-\\s)", "var(--")
687+
.replaceAll("\\)(var\\(--)", ") var(--");
688+
}
656689
}

src/test/resources/calc.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@
55
right: calc(((100% - 1200px) /2) + 16px);
66
height:calc(50% + 4px);
77
bottom:calc(100vh - 20px);
8+
}
9+
10+
.test-calc-edge-cases {
11+
left: calc( 100% - calc( 50px + 10px ) );
12+
right: calc(100% - calc(50px - -10px));
813
}

src/test/resources/calc.css.min

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
.test-calc{top:calc(-100vw + 4em) !important;left:calc(50% - (100px * 2));width:calc(25% + 10px);right:calc(((100% - 1200px) / 2) + 16px);height:calc(50% + 4px);bottom:calc(100vh - 20px)}
1+
.test-calc{top:calc(-100vw + 4em) !important;left:calc(50% - (100px * 2));width:calc(25% + 10px);right:calc(((100% - 1200px) / 2) + 16px);height:calc(50% + 4px);bottom:calc(100vh - 20px)}.test-calc-edge-cases{left:calc(100% - calc(50px + 10px));right:calc(100% - calc(50px - -10px))}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.unclosed-calc {
2+
bottom:calc( calc(100vh - 20px )
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.unclosed-calc{bottom:calc(calc(100vh - 20px)}

src/test/resources/shape.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* Example from: https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape/shape */
2+
.foo {
3+
/* <fill-rule> */
4+
clip-path: shape(nonzero from 0 0, line to 10px 10px);
5+
6+
/* <move-command>, <line-command>, and close */
7+
offset-path: shape(from 10px 10px, move by 10px 5px, line by 20px 40%, close);
8+
9+
/* <hvline-command> */
10+
offset-path: shape(from 10px 10px, hline by 50px, vline to 5rem);
11+
12+
/* <curve-command> */
13+
offset-path: shape(
14+
from 10px 10px,
15+
curve to 80px 80px with 160px 1px / 20% 16px
16+
);
17+
18+
/* <smooth-command> */
19+
offset-path: shape(from 10px 10px, smooth to 100px 50pt);
20+
21+
/* <arc-command> */
22+
offset-path: shape(
23+
from 5% 0.5rem,
24+
arc to 80px 1pt of 10% ccw large rotate 25deg
25+
);
26+
27+
/* Using a CSS math function */
28+
offset-path: shape(
29+
from 5px -5%,
30+
hline to 50px,
31+
vline by calc(0% + 160px),
32+
hline by 70.5px,
33+
close,
34+
vline by 60px
35+
);
36+
37+
clip-path: shape(
38+
evenodd from 10px 10px,
39+
curve to 60px 20% with 40px 0,
40+
smooth to 90px 0,
41+
curve by -20px 60% with 10% 40px / 20% 20px,
42+
smooth by -40% -10px with -10px 70px,
43+
close
44+
);
45+
}

src/test/resources/shape.css.min

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.foo{clip-path:shape(nonzero from 0 0,line to 10px 10px);offset-path:shape(from 10px 10px,move by 10px 5px,line by 20px 40%,close);offset-path:shape(from 10px 10px,hline by 50px,vline to 5rem);offset-path:shape(from 10px 10px,curve to 80px 80px with 160px 1px / 20% 16px);offset-path:shape(from 10px 10px,smooth to 100px 50pt);offset-path:shape(from 5% .5rem,arc to 80px 1pt of 10% ccw large rotate 25deg);offset-path:shape(from 5px -5%,hline to 50px,vline by calc(0% + 160px),hline by 70.5px,close,vline by 60px);clip-path:shape(evenodd from 10px 10px,curve to 60px 20% with 40px 0,smooth to 90px 0,curve by -20px 60% with 10% 40px / 20% 20px,smooth by -40% -10px with -10px 70px,close)}

src/test/resources/unicode.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.arrow::before {
2+
content: "↓";
3+
}

src/test/resources/unicode.css.min

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.arrow::before{content:"↓"}

0 commit comments

Comments
 (0)