[richfaces-svn-commits] JBoss Rich Faces SVN: r4655 - in branches/3.1.x/framework/impl/src: main/java/org/ajax4jsf/css and 3 other directories.
richfaces-svn-commits at lists.jboss.org
richfaces-svn-commits at lists.jboss.org
Mon Dec 10 09:48:48 EST 2007
Author: andrei_exadel
Date: 2007-12-10 09:48:48 -0500 (Mon, 10 Dec 2007)
New Revision: 4655
Added:
branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/css/
branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/css/CssCompressor.java
branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/CountingOutputWriter.java
branches/3.1.x/framework/impl/src/test/java/org/ajax4jsf/css/
branches/3.1.x/framework/impl/src/test/java/org/ajax4jsf/css/CssCompressorTest.java
Modified:
branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/TemplateCSSRenderer.java
Log:
RF-1349
Added: branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/css/CssCompressor.java
===================================================================
--- branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/css/CssCompressor.java (rev 0)
+++ branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/css/CssCompressor.java 2007-12-10 14:48:48 UTC (rev 4655)
@@ -0,0 +1,154 @@
+/*
+ * YUI Compressor
+ * Author: Julien Lecomte <jlecomte at yahoo-inc.com>
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * Code licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ *
+ * This code is a port of Isaac Schlueter's cssmin utility.
+ */
+
+package org.ajax4jsf.css;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class CssCompressor {
+
+ private StringBuffer srcsb = null;
+
+ public CssCompressor(StringBuffer buffer) throws IOException {
+ srcsb = buffer;
+ }
+
+ public int compress(Writer out, int linebreakpos)
+ throws IOException {
+
+ Pattern p;
+ Matcher m;
+ String css;
+ StringBuffer sb;
+ int startIndex, endIndex;
+ int bytesLength;
+
+ // Remove all comment blocks...
+ sb = new StringBuffer(srcsb.toString());
+ while ((startIndex = sb.indexOf("/*")) >= 0) {
+ endIndex = sb.indexOf("*/", startIndex + 2);
+ if (endIndex >= startIndex + 2)
+ sb.delete(startIndex, endIndex + 2);
+ }
+
+ css = sb.toString();
+
+ // Normalize all whitespace strings to single spaces. Easier to work with that way.
+ css = css.replaceAll("\\s+", " ");
+
+ // 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("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)");
+ m = p.matcher(css);
+ while (m.find()) {
+ String s = m.group();
+ s = s.replaceAll(":", "___PSEUDOCLASSCOLON___");
+ m.appendReplacement(sb, s);
+ }
+ m.appendTail(sb);
+ css = sb.toString();
+ css = css.replaceAll("\\s+([!{};:>+\\(\\)\\],])", "$1");
+ css = css.replaceAll("___PSEUDOCLASSCOLON___", ":");
+
+ // Remove the spaces after the things that should not have spaces after them.
+ css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1");
+
+ // Add the semicolon where it's missing.
+ css = css.replaceAll("([^;\\}])}", "$1;}");
+
+ // Replace 0(px,em,%) with 0.
+ css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2");
+
+ // Replace 0 0 0 0; with 0.
+ css = css.replaceAll(":0 0 0 0;", ":0;");
+ css = css.replaceAll(":0 0 0;", ":0;");
+ css = css.replaceAll(":0 0;", ":0;");
+ // Replace background-position:0; with background-position:0 0;
+ css = css.replaceAll("background-position:0;", "background-position:0 0;");
+
+ // Replace 0.6 to .6, but only when preceded by : or a white-space
+ css = css.replaceAll("(:|\\s)0+\\.(\\d+)", "$1.$2");
+
+ // Shorten colors from rgb(51,102,153) to #336699
+ // This makes it more likely that it'll get further compressed in the next step.
+ p = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)");
+ m = p.matcher(css);
+ sb = new StringBuffer();
+ while (m.find()) {
+ String[] rgbcolors = m.group(1).split(",");
+ StringBuffer hexcolor = new StringBuffer("#");
+ for (int i = 0; i < rgbcolors.length; i++) {
+ int val = Integer.parseInt(rgbcolors[i]);
+ if (val < 16) {
+ hexcolor.append("0");
+ }
+ hexcolor.append(Integer.toHexString(val));
+ }
+ m.appendReplacement(sb, hexcolor.toString());
+ }
+ m.appendTail(sb);
+ css = sb.toString();
+
+ // Shorten colors from #AABBCC to #ABC. Note that we want to make sure
+ // the color is not preceded by either ", " or =. Indeed, the property
+ // filter: chroma(color="#FFFFFF");
+ // would become
+ // filter: chroma(color="#FFF");
+ // which makes the filter break in IE.
+ p = Pattern.compile("([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])");
+ m = p.matcher(css);
+ sb = new StringBuffer();
+ while (m.find()) {
+ // Test for AABBCC pattern
+ if (m.group(3).equalsIgnoreCase(m.group(4)) &&
+ m.group(5).equalsIgnoreCase(m.group(6)) &&
+ m.group(7).equalsIgnoreCase(m.group(8))) {
+ m.appendReplacement(sb, m.group(1) + m.group(2) + "#" + m.group(3) + m.group(5) + m.group(7));
+ } else {
+ m.appendReplacement(sb, m.group());
+ }
+ }
+ m.appendTail(sb);
+ css = sb.toString();
+
+ // Remove empty rules.
+ css = css.replaceAll("[^\\}]+\\{;\\}", "");
+
+ if (linebreakpos >= 0) {
+ // Some source control tools don't like it when files containing lines longer
+ // than, say 8000 characters, are checked in. The linebreak option is used in
+ // that case to split long lines after a specific column.
+ int i = 0;
+ int linestartpos = 0;
+ sb = new StringBuffer(css);
+ while (i < sb.length()) {
+ char c = sb.charAt(i++);
+ if (c == '}' && i - linestartpos > linebreakpos) {
+ sb.insert(i, '\n');
+ linestartpos = i;
+ }
+ }
+
+ css = sb.toString();
+ }
+
+ // Trim the final string (for any leading or trailing white spaces)
+ css = css.trim();
+ bytesLength = css.length() * 2;
+ // Write the output...
+ out.write(css);
+ return bytesLength;
+ }
+}
Added: branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/CountingOutputWriter.java
===================================================================
--- branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/CountingOutputWriter.java (rev 0)
+++ branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/CountingOutputWriter.java 2007-12-10 14:48:48 UTC (rev 4655)
@@ -0,0 +1,110 @@
+/*
+ * CountingOutputWriter.java Date created: 21.11.2007
+ * Last modified by: $Author$
+ * $Revision$ $Date$
+ */
+
+package org.ajax4jsf.resource;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Class provides custom writer implementation with counting of bytes written
+ * Is using for replacement of css component writer
+ * @author Andrey Markavtsov
+ */
+public class CountingOutputWriter extends Writer {
+
+ /** count of written bytes */
+ private int written = 0;
+
+ /** Size of char type */
+ private static final int sizeOfChar = 2;
+
+ /** Size of int type */
+ private static final int sizeOfInt = 4;
+
+ /** Buffer to store bytes written */
+ private StringBuffer buffer;
+
+ /**
+ * Default constructor
+ */
+ public CountingOutputWriter() {
+ super();
+ this.buffer = new StringBuffer();
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.Writer#close()
+ */
+ public void close() throws IOException {
+ ;
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.Writer#flush()
+ */
+ public void flush() throws IOException {
+ ;
+ }
+
+ /** Methods appends chars written to buffer
+ * @param cbuf - chars to be written
+ * @param off - offset
+ * @param len - length of bytes
+ */
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ buffer.append(cbuf, off, len);
+ written += len * sizeOfChar;
+ }
+
+ /** Methods appends chars written to buffer
+ * @param cbuf - chars to be written
+ */
+ public void write(char[] cbuf) throws IOException {
+ buffer.append(cbuf);
+ written += cbuf.length * sizeOfChar;
+ }
+
+ /** Methods appends int written to buffer
+ * @param c - int to be written
+ */
+ public void write(int c) throws IOException {
+ buffer.append(c);
+ written += sizeOfInt;
+ }
+
+ /** Methods appends string written to buffer
+ * @param str - string to be written
+ * @param off - offset
+ * @param len - length of bytes
+ */
+ public void write(String str, int off, int len) throws IOException {
+ buffer.append(str, off, len);
+ written += len * sizeOfChar;
+ }
+
+ /** Methods appends string written to buffer
+ * @param str - string to be written
+ */
+ public void write(String str) throws IOException {
+ buffer.append(str);
+ written += str.length() * sizeOfChar;
+ }
+
+ /** Methods gets written bytes count
+ * @return written count of bytes
+ */
+ public int getWritten() {
+ return written;
+ }
+
+ /** Methods gets content of written bytes
+ * @return buffer
+ */
+ public StringBuffer getContent () {
+ return buffer;
+ }
+}
\ No newline at end of file
Modified: branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/TemplateCSSRenderer.java
===================================================================
--- branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/TemplateCSSRenderer.java 2007-12-10 14:37:16 UTC (rev 4654)
+++ branches/3.1.x/framework/impl/src/main/java/org/ajax4jsf/resource/TemplateCSSRenderer.java 2007-12-10 14:48:48 UTC (rev 4655)
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.Writer;
import java.nio.ByteBuffer;
import javax.faces.FacesException;
@@ -33,12 +34,11 @@
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
+import org.ajax4jsf.css.CssCompressor;
import org.ajax4jsf.renderkit.RendererBase;
import org.ajax4jsf.renderkit.compiler.HtmlCompiler;
import org.ajax4jsf.renderkit.compiler.PreparedTemplate;
import org.ajax4jsf.renderkit.compiler.TemplateContext;
-import org.ajax4jsf.resource.InternetResource;
-import org.ajax4jsf.resource.ResourceContext;
import org.richfaces.skin.SkinFactory;
/**
@@ -48,6 +48,9 @@
public class TemplateCSSRenderer extends StyleRenderer {
private static final String COMPILED_TEMPLATE_PROPERTY = "compiled-template";
+
+ /** Parameter allows switch on/off comressing for css */
+ private static final String COMPRESS_STYLE_PARAMETER = "org.ajax4jsf.COMPRESS_STYLE";
private RendererBase renderer = new RendererBase() {
@@ -62,8 +65,13 @@
*/
public int send(InternetResource base, ResourceContext context) throws IOException {
PreparedTemplate template = null;
+ CountingOutputWriter countingOutputWriter = new CountingOutputWriter();
template = getTemplate(base, context);
FacesContext facesContext = FacesContext.getCurrentInstance();
+ boolean _CompressStyleOn = !"false".equals(facesContext.getExternalContext()
+ .getInitParameter(COMPRESS_STYLE_PARAMETER));
+ Writer writer = context.getWriter();
+ int bytesLength;
if(null != facesContext) {
// Create responseWriter.
String defaultRenderKitId = facesContext.getApplication().getDefaultRenderKitId();
@@ -73,19 +81,34 @@
RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
RenderKit renderKit = renderKitFactory.getRenderKit(facesContext,defaultRenderKitId);
// TODO - handle response encoding
- ResponseWriter responseWriter = renderKit.createResponseWriter(context.getWriter(),null,"UTF-8");
+
+ ResponseWriter responseWriter = renderKit.createResponseWriter(countingOutputWriter,null,"UTF-8");
facesContext.setResponseWriter(responseWriter);
responseWriter.startDocument();
+
// TODO - parameters and mock renderer/component ?
// for first time, this template only allow skin or faces variables interaction
template.encode(renderer,facesContext,null);
responseWriter.endDocument();
responseWriter.flush();
responseWriter.close();
+
+ if (_CompressStyleOn) {
+ CssCompressor compressor = new CssCompressor(countingOutputWriter.getContent()); // Compressing css document and printing result in response stream
+ bytesLength = compressor.compress(writer, -1);
+ writer.flush();
+ writer.close();
+ } else {
+ writer.write(countingOutputWriter.getContent().toString()); // Write not compressed style content
+ bytesLength = countingOutputWriter.getWritten();
+ writer.flush();
+ writer.close();
+ }
+
} else {
throw new FacesException("FacesContext for resource from template "+base.getKey()+" is null");
}
- return 0;
+ return bytesLength;
}
/**
Added: branches/3.1.x/framework/impl/src/test/java/org/ajax4jsf/css/CssCompressorTest.java
===================================================================
--- branches/3.1.x/framework/impl/src/test/java/org/ajax4jsf/css/CssCompressorTest.java (rev 0)
+++ branches/3.1.x/framework/impl/src/test/java/org/ajax4jsf/css/CssCompressorTest.java 2007-12-10 14:48:48 UTC (rev 4655)
@@ -0,0 +1,87 @@
+/*
+ * CssCompressorTest.java Date created: 21.11.2007
+ * Last modified by: $Author$
+ * $Revision$ $Date$
+ */
+
+package org.ajax4jsf.css;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.ajax4jsf.resource.CountingOutputWriter;
+
+/**
+ * Test case for css compressing process
+ * @author Andrey Markavtsov
+ *
+ */
+public class CssCompressorTest extends TestCase {
+
+ /** Length of correctly compressed css example */
+ private static final int lengthCompressed = 610;
+
+ /** css example to be comressed */
+ private static final String cssExample =
+ "HTML { \n"+
+ "MARGIN-BOTTOM: 0.01em; HEIGHT: 100%; BACKGROUND-COLOR: #ffffff;\n" +
+ "}\n" +
+ "TD {\n" +
+ "FONT-SIZE: 10px; COLOR: #000000; FONT-FAMILY: verdana, arial\n" +
+ "}\n" +
+ "TH {\n" +
+ "FONT-WEIGHT: bold; FONT-SIZE: 10px; COLOR: #336699; FONT-FAMILY: verdana, arial; BACKGROUND-COLOR: #ffffff; text-align:left;\n" +
+ "}\n" +
+ ".header {\n" +
+ "FONT-WEIGHT: bold; FONT-SIZE: 11px; COLOR: #000000; FONT-FAMILY: verdana, arial\n" +
+ "}\n";
+
+ /**
+ * Constructor
+ * @param name
+ */
+ public CssCompressorTest(String name) {
+ super(name);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ // TODO Auto-generated method stub
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ // TODO Auto-generated method stub
+ super.tearDown();
+ }
+
+
+ /**
+ * Test method
+ * @throws IOException
+ */
+ public void testCssCompressor () throws IOException {
+
+ StringBuffer cssBuffer = new StringBuffer(cssExample);
+ CssCompressor compressor = new CssCompressor(cssBuffer);
+ CountingOutputWriter writer = new CountingOutputWriter();
+ compressor.compress(writer, -1);
+
+ // compressed length should equal
+ assertEquals(writer.getWritten(), lengthCompressed);
+
+ }
+
+
+
+
+}
More information about the richfaces-svn-commits
mailing list