-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TAP5-2606 - Updating YUI CssCompressor to the latest version from its…
… github master branch
- Loading branch information
Showing
1 changed file
with
83 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,9 +14,9 @@ | |
import java.io.IOException; | ||
import java.io.Reader; | ||
import java.io.Writer; | ||
import java.util.ArrayList; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import java.util.regex.Matcher; | ||
import java.util.ArrayList; | ||
|
||
public class CssCompressor { | ||
|
||
|
@@ -30,28 +30,33 @@ public CssCompressor(Reader in) throws IOException { | |
} | ||
} | ||
|
||
// Leave data urls alone to increase parse performance. | ||
protected String extractDataUrls(String css, ArrayList preservedTokens) { | ||
/** | ||
* @param css - full css string | ||
* @param preservedToken - token to preserve | ||
* @param tokenRegex - regex to find token | ||
* @param removeWhiteSpace - remove any white space in the token | ||
* @param preservedTokens - array of token values | ||
* @return | ||
*/ | ||
protected String preserveToken(String css, String preservedToken, | ||
String tokenRegex, boolean removeWhiteSpace, ArrayList preservedTokens) { | ||
|
||
int maxIndex = css.length() - 1; | ||
int appendIndex = 0; | ||
|
||
StringBuffer sb = new StringBuffer(); | ||
|
||
Pattern p = Pattern.compile("(?i)url\\(\\s*([\"']?)data\\:"); | ||
Pattern p = Pattern.compile(tokenRegex); | ||
Matcher m = p.matcher(css); | ||
|
||
/* | ||
* Since we need to account for non-base64 data urls, we need to handle | ||
* ' and ) being part of the data string. Hence switching to indexOf, | ||
* to determine whether or not we have matching string terminators and | ||
* handling sb appends directly, instead of using matcher.append* methods. | ||
*/ | ||
|
||
while (m.find()) { | ||
int startIndex = m.start() + (preservedToken.length() + 1); | ||
String terminator = m.group(1); | ||
|
||
int startIndex = m.start() + 4; // "url(".length() | ||
String terminator = m.group(1); // ', " or empty (not quoted) | ||
// skip this, if CSS was already copied to "sb" upto this position | ||
if (m.start() < appendIndex) { | ||
continue; | ||
} | ||
|
||
if (terminator.length() == 0) { | ||
terminator = ")"; | ||
|
@@ -63,7 +68,9 @@ protected String extractDataUrls(String css, ArrayList preservedTokens) { | |
while(foundTerminator == false && endIndex+1 <= maxIndex) { | ||
endIndex = css.indexOf(terminator, endIndex+1); | ||
|
||
if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) { | ||
if (endIndex <= 0) { | ||
break; | ||
} else if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) { | ||
foundTerminator = true; | ||
if (!")".equals(terminator)) { | ||
endIndex = css.indexOf(")", endIndex); | ||
|
@@ -76,10 +83,11 @@ protected String extractDataUrls(String css, ArrayList preservedTokens) { | |
|
||
if (foundTerminator) { | ||
String token = css.substring(startIndex, endIndex); | ||
token = token.replaceAll("\\s+", ""); | ||
if(removeWhiteSpace) | ||
token = token.replaceAll("\\s+", ""); | ||
preservedTokens.add(token); | ||
|
||
String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)"; | ||
String preserver = preservedToken + "(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)"; | ||
sb.append(preserver); | ||
|
||
appendIndex = endIndex + 1; | ||
|
@@ -95,20 +103,6 @@ protected String extractDataUrls(String css, ArrayList preservedTokens) { | |
return sb.toString(); | ||
} | ||
|
||
private String preserveOldIESpecificMatrixDefinition(String css, ArrayList preservedTokens) { | ||
StringBuffer sb = new StringBuffer(); | ||
Pattern p = Pattern.compile("\\s*filter:\\s*progid:DXImageTransform.Microsoft.Matrix\\(([^\\)]+)\\);"); | ||
Matcher m = p.matcher(css); | ||
while (m.find()) { | ||
String token = m.group(1); | ||
preservedTokens.add(token); | ||
String preserver = "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"; | ||
m.appendReplacement(sb, "filter:progid:DXImageTransform.Microsoft.Matrix(" + preserver + ");"); | ||
} | ||
m.appendTail(sb); | ||
return sb.toString(); | ||
} | ||
|
||
public void compress(Writer out, int linebreakpos) | ||
throws IOException { | ||
|
||
|
@@ -126,7 +120,6 @@ public void compress(Writer out, int linebreakpos) | |
int totallen = css.length(); | ||
String placeholder; | ||
|
||
css = this.extractDataUrls(css, preservedTokens); | ||
|
||
StringBuffer sb = new StringBuffer(css); | ||
|
||
|
@@ -144,6 +137,12 @@ public void compress(Writer out, int linebreakpos) | |
} | ||
css = sb.toString(); | ||
|
||
|
||
css = this.preserveToken(css, "url", "(?i)url\\(\\s*([\"']?)data\\:", true, preservedTokens); | ||
css = this.preserveToken(css, "calc", "(?i)calc\\(\\s*([\"']?)", false, preservedTokens); | ||
css = this.preserveToken(css, "progid:DXImageTransform.Microsoft.Matrix", "(?i)progid:DXImageTransform.Microsoft.Matrix\\s*([\"']?)", false, preservedTokens); | ||
|
||
|
||
// preserve strings so their content doesn't get accidentally minified | ||
sb = new StringBuffer(); | ||
p = Pattern.compile("(\"([^\\\\\"]|\\\\.|\\\\)*\")|(\'([^\\\\\']|\\\\.|\\\\)*\')"); | ||
|
@@ -213,17 +212,21 @@ public void compress(Writer out, int linebreakpos) | |
css = css.replace("/*" + placeholder + "*/", ""); | ||
} | ||
|
||
|
||
// preserve \9 IE hack | ||
final String backslash9 = "\\9"; | ||
while (css.indexOf(backslash9) > -1) { | ||
preservedTokens.add(backslash9); | ||
css = css.replace(backslash9, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); | ||
} | ||
|
||
// Normalize all whitespace strings to single spaces. Easier to work with that way. | ||
css = css.replaceAll("\\s+", " "); | ||
|
||
css = this.preserveOldIESpecificMatrixDefinition(css, preservedTokens); | ||
|
||
// Remove the spaces before the things that should not have spaces before them. | ||
// But, be careful not to turn "p :link {...}" into "p:link{...}" | ||
// Swap out any pseudo-class colons with the token, and then swap back. | ||
sb = new StringBuffer(); | ||
p = Pattern.compile("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)"); | ||
p = Pattern.compile("(^|\\})((^|([^\\{:])+):)+([^\\{]*\\{)"); | ||
m = p.matcher(css); | ||
while (m.find()) { | ||
String s = m.group(); | ||
|
@@ -258,7 +261,8 @@ public void compress(Writer out, int linebreakpos) | |
p = Pattern.compile("(?i)^(.*)(@charset)( \"[^\"]*\";)"); | ||
m = p.matcher(css); | ||
while (m.find()) { | ||
m.appendReplacement(sb, m.group(2).toLowerCase() + m.group(3) + m.group(1)); | ||
String s = m.group(1).replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "\\\\\\$"); | ||
m.appendReplacement(sb, m.group(2).toLowerCase() + m.group(3) + s); | ||
} | ||
m.appendTail(sb); | ||
css = sb.toString(); | ||
|
@@ -325,12 +329,29 @@ public void compress(Writer out, int linebreakpos) | |
css = css.replaceAll(";+}", "}"); | ||
|
||
// Replace 0(px,em,%) with 0. | ||
css = css.replaceAll("(?i)(^|[^0-9])(?:0?\\.)?0(?:px|em|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)", "$10"); | ||
String oldCss; | ||
p = Pattern.compile("(?i)(^|: ?)((?:[0-9a-z-.]+ )*?)?(?:0?\\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)"); | ||
do { | ||
oldCss = css; | ||
m = p.matcher(css); | ||
css = m.replaceAll("$1$20"); | ||
} while (!(css.equals(oldCss))); | ||
|
||
// Replace 0(px,em,%) with 0 inside groups (e.g. -MOZ-RADIAL-GRADIENT(CENTER 45DEG, CIRCLE CLOSEST-SIDE, ORANGE 0%, RED 100%)) | ||
p = Pattern.compile("(?i)\\( ?((?:[0-9a-z-.]+[ ,])*)?(?:0?\\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)"); | ||
do { | ||
oldCss = css; | ||
m = p.matcher(css); | ||
css = m.replaceAll("($10"); | ||
} while (!(css.equals(oldCss))); | ||
|
||
// Replace x.0(px,em,%) with x(px,em,%). | ||
css = css.replaceAll("([0-9])\\.0(px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz| |;)", "$1$2"); | ||
|
||
// Replace 0 0 0 0; with 0. | ||
css = css.replaceAll(":0 0 0 0(;|})", ":0$1"); | ||
css = css.replaceAll(":0 0 0(;|})", ":0$1"); | ||
css = css.replaceAll(":0 0(;|})", ":0$1"); | ||
css = css.replaceAll("(?<!flex):0 0(;|})", ":0$1"); | ||
|
||
|
||
// Replace background-position:0; with background-position:0 0; | ||
|
@@ -398,8 +419,8 @@ public void compress(Writer out, int linebreakpos) | |
sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)); | ||
} else { | ||
if( m.group(2).equalsIgnoreCase(m.group(3)) && | ||
m.group(4).equalsIgnoreCase(m.group(5)) && | ||
m.group(6).equalsIgnoreCase(m.group(7))) { | ||
m.group(4).equalsIgnoreCase(m.group(5)) && | ||
m.group(6).equalsIgnoreCase(m.group(7))) { | ||
|
||
// #AABBCC pattern | ||
sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase()); | ||
|
@@ -477,14 +498,33 @@ public void compress(Writer out, int linebreakpos) | |
css = css.replaceAll(";;+", ";"); | ||
|
||
// restore preserved comments and strings | ||
for(i = preservedTokens.size() - 1; i >= 0 ; i--) { | ||
for(i = 0, max = preservedTokens.size(); i < max; i++) { | ||
css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i).toString()); | ||
} | ||
|
||
// Add spaces back in between operators for css calc function | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/calc | ||
// Added by Eric Arnol-Martin ([email protected]) | ||
sb = new StringBuffer(); | ||
p = Pattern.compile("calc\\([^\\)]*\\)"); | ||
m = p.matcher(css); | ||
while (m.find()) { | ||
String s = m.group(); | ||
|
||
s = s.replaceAll("(?<=[-|%|px|em|rem|vw|\\d]+)\\+", " + "); | ||
s = s.replaceAll("(?<=[-|%|px|em|rem|vw|\\d]+)\\-", " - "); | ||
s = s.replaceAll("(?<=[-|%|px|em|rem|vw|\\d]+)\\*", " * "); | ||
s = s.replaceAll("(?<=[-|%|px|em|rem|vw|\\d]+)\\/", " / "); | ||
|
||
m.appendReplacement(sb, s); | ||
} | ||
m.appendTail(sb); | ||
css = sb.toString(); | ||
|
||
// Trim the final string (for any leading or trailing white spaces) | ||
css = css.trim(); | ||
|
||
// Write the output... | ||
out.write(css); | ||
} | ||
} | ||
} |