Revision: 9760
Author: [email protected]
Date: Wed Feb 23 15:55:53 2011
Log: Make a CssResource available on the server side as well as client side
Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=9760
Added:
/trunk/user/src/com/google/gwt/resources/css/CheckStaticCssVisitor.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssSubstitution.java
Modified:
/trunk/user/src/com/google/gwt/resources/css/ClassRenamer.java
/trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
/trunk/user/src/com/google/gwt/resources/css/ast/CollapsedNode.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssDef.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssIf.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssMediaRule.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssNoFlip.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssNode.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssPageRule.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssProperty.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssRule.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssSelector.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssSprite.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssStylesheet.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssUnknownAtRule.java
/trunk/user/src/com/google/gwt/resources/css/ast/CssUrl.java
/trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/resources/css/CheckStaticCssVisitor.java
Wed Feb 23 15:55:53 2011
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.resources.css;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.resources.css.ast.CssNode;
+import com.google.gwt.resources.css.ast.CssStylesheet;
+import com.google.gwt.resources.css.ast.CssVisitor;
+
+import java.util.List;
+
+/**
+* Check a stylesheet to ensure that all of its components are
+* statically-evaluable.
+*/
+public class CheckStaticCssVisitor extends CssVisitor {
+
+ /**
+ * A fast-fail check to determine if a stylesheet is statically-evaluable.
+ */
+ public static boolean isStatic(CssStylesheet sheet) {
+ return new CheckStaticCssVisitor(TreeLogger.NULL, true).execImpl(sheet);
+ }
+
+ /**
+ * Returns <code>true</code> if the stylsheet is statically-evaluable.
Nodes
+ * that are not statically-evaluable will be reported to the associated
+ * logger.
+ */
+ public static boolean report(TreeLogger logger, CssStylesheet sheet) {
+ return new CheckStaticCssVisitor(logger, false).execImpl(sheet);
+ }
+
+ private boolean error;
+ private final boolean fastFail;
+ private final TreeLogger logger;
+
+ private CheckStaticCssVisitor(TreeLogger logger, boolean fastFail) {
+ this.logger = logger.branch(TreeLogger.DEBUG,
+ "Checking external stylesheet for dynamic content");
+ this.fastFail = fastFail;
+ }
+
+ @Override
+ protected void doAccept(List<? extends CssNode> list) {
+ for (CssNode node : list) {
+ if (error && fastFail) {
+ return;
+ }
+ doAccept(node);
+ }
+ }
+
+ @Override
+ protected <T extends CssNode> T doAccept(T node) {
+ if (!node.isStatic()) {
+ error(node);
+ }
+
+ if (error && fastFail) {
+ // Just stop
+ return node;
+ } else {
+ return super.doAccept(node);
+ }
+ }
+
+ @Override
+ protected void doAcceptWithInsertRemove(List<? extends CssNode> list) {
+ doAccept(list);
+ }
+
+ void error(CssNode node) {
+ logger.log(TreeLogger.ERROR, "The CSS node " + node.toString()
+ + " cannot be statically evaluated");
+ error = true;
+ }
+
+ private boolean execImpl(CssStylesheet sheet) {
+ accept(sheet);
+ return !error;
+ }
+}
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssSubstitution.java
Wed Feb 23 15:55:53 2011
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+
+package com.google.gwt.resources.css.ast;
+
+/**
+ * A tag interface that indicates that a CssNode may be used as a
substitution
+ * value.
+ */
+public interface CssSubstitution { }
+
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ClassRenamer.java Thu Sep
2 06:12:48 2010
+++ /trunk/user/src/com/google/gwt/resources/css/ClassRenamer.java Wed Feb
23 15:55:53 2011
@@ -85,25 +85,22 @@
* Records replacements that have actually been performed.
*/
private final Map<JMethod, String> actualReplacements = new
IdentityHashMap<JMethod, String>();
+ private final Map<String, Map<JMethod, String>>
classReplacementsWithPrefix;
private final Set<String> cssDefs = new HashSet<String>();
-
- /**
- * The task-list of replacements to perform in the stylesheet.
- */
- private final Map<String, Replacement> potentialReplacements;
+ private final Set<String> externalClasses;
private final TreeLogger logger;
private final Set<JMethod> missingClasses;
private final boolean strict;
private final Set<String> unknownClasses = new HashSet<String>();
+
public ClassRenamer(TreeLogger logger,
Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
boolean strict, Set<String> externalClasses) {
this.logger = logger.branch(TreeLogger.DEBUG, "Replacing CSS class
names");
+ this.classReplacementsWithPrefix = classReplacementsWithPrefix;
this.strict = strict;
-
- potentialReplacements =
computeReplacements(classReplacementsWithPrefix,
- externalClasses);
+ this.externalClasses = externalClasses;
// Require a definition for all classes in the default namespace
assert classReplacementsWithPrefix.containsKey("");
@@ -119,6 +116,10 @@
@Override
public void endVisit(CssSelector x, Context ctx) {
+ final Map<String, Replacement> potentialReplacements;
+ potentialReplacements =
computeReplacements(classReplacementsWithPrefix,
+ externalClasses);
+
String sel = x.getSelector();
int originalLength = sel.length();
@@ -247,6 +248,10 @@
String sourceClassName = method.getName();
String obfuscatedClassName = entry.getValue();
+ if (cssDefs.contains(sourceClassName)) {
+ continue;
+ }
+
ClassName className = method.getAnnotation(ClassName.class);
if (className != null) {
sourceClassName = className.value();
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
Wed Mar 3 06:58:58 2010
+++ /trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
Wed Feb 23 15:55:53 2011
@@ -29,6 +29,7 @@
import com.google.gwt.resources.css.ast.CssRule;
import com.google.gwt.resources.css.ast.CssSelector;
import com.google.gwt.resources.css.ast.CssSprite;
+import com.google.gwt.resources.css.ast.CssSubstitution;
import com.google.gwt.resources.css.ast.CssUnknownAtRule;
import com.google.gwt.resources.css.ast.CssUrl;
import com.google.gwt.resources.css.ast.CssVisitor;
@@ -49,7 +50,7 @@
private boolean needsComma;
private final boolean substituteDots;
- private final SortedMap<Integer, List<CssNode>> substitutionPositions =
new TreeMap<Integer, List<CssNode>>();
+ private final SortedMap<Integer, List<CssSubstitution>>
substitutionPositions = new TreeMap<Integer, List<CssSubstitution>>();
/**
* Constructor.
@@ -116,7 +117,7 @@
out.print(x.getRule());
}
- public SortedMap<Integer, List<CssNode>> getSubstitutionPositions() {
+ public SortedMap<Integer, List<CssSubstitution>>
getSubstitutionPositions() {
return substitutionPositions;
}
@@ -262,7 +263,7 @@
return false;
}
- private void addSubstitition(CssNode node) {
+ private <T extends CssNode & CssSubstitution> void addSubstitition(T
node) {
if (substituteDots) {
out.printOpt(".....");
out.newlineOpt();
@@ -271,7 +272,7 @@
if (substitutionPositions.containsKey(position)) {
substitutionPositions.get(position).add(node);
} else {
- List<CssNode> nodes = new ArrayList<CssNode>();
+ List<CssSubstitution> nodes = new ArrayList<CssSubstitution>();
nodes.add(node);
substitutionPositions.put(position, nodes);
}
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CollapsedNode.java Tue
Mar 17 11:59:31 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CollapsedNode.java Wed
Feb 23 15:55:53 2011
@@ -37,6 +37,11 @@
public List<CssNode> getNodes() {
return nodes;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
visitor.acceptWithInsertRemove(getNodes());
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssDef.java Wed Mar 11
17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssDef.java Wed Feb 23
15:55:53 2011
@@ -38,6 +38,11 @@
public List<Value> getValues() {
return values;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
visitor.visit(this, context);
=======================================
---
/trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
Sat Oct 10 13:50:11 2009
+++
/trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
Wed Feb 23 15:55:53 2011
@@ -31,6 +31,11 @@
return classes;
}
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
+
public void traverse(CssVisitor visitor, Context context) {
visitor.visit(this, context);
visitor.endVisit(this, context);
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssIf.java Wed Mar 11
17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssIf.java Wed Feb 23
15:55:53 2011
@@ -22,7 +22,7 @@
* A GWTCSS if statement. The elif and else constructs are modeled as
nested if
* statement is the elseNodes.
*/
-public class CssIf extends CssNode implements HasNodes {
+public class CssIf extends CssNode implements CssSubstitution, HasNodes {
private final List<CssNode> elseNodes = new ArrayList<CssNode>();
private final List<CssNode> nodes = new ArrayList<CssNode>();
private String expression;
@@ -53,6 +53,14 @@
public boolean isNegated() {
return isNegated;
}
+
+ /**
+ * A CssIf is static if it uses only a deferred-binding property.
+ */
+ @Override
+ public boolean isStatic() {
+ return expression == null;
+ }
public void setExpression(String expression) {
this.expression = expression;
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssMediaRule.java Wed
Mar 11 17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssMediaRule.java Wed
Feb 23 15:55:53 2011
@@ -32,6 +32,11 @@
public List<CssNode> getNodes() {
return nodes;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
if (visitor.visit(this, context)) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssNoFlip.java Wed Mar
11 17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssNoFlip.java Wed Feb
23 15:55:53 2011
@@ -28,6 +28,11 @@
public List<CssNode> getNodes() {
return nodes;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
if (visitor.visit(this, context)) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssNode.java Wed Mar
11 17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssNode.java Wed Feb
23 15:55:53 2011
@@ -22,6 +22,13 @@
* The basic type that composes a CSS tree.
*/
public abstract class CssNode implements CssVisitable {
+
+ /**
+ * Indicates whether or not the CssNode requires runtime evaluation. This
+ * method should not include any information from child nodes.
+ */
+ public abstract boolean isStatic();
+
@Override
public String toString() {
DefaultTextOutput out = new DefaultTextOutput(false);
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssPageRule.java Wed
Mar 11 17:58:41 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssPageRule.java Wed
Feb 23 15:55:53 2011
@@ -32,6 +32,11 @@
public String getPseudoPage() {
return pseudoPage;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void setPseudoPage(String pseudoPage) {
this.pseudoPage = pseudoPage;
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssProperty.java Fri
Jan 15 11:17:28 2010
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssProperty.java Wed
Feb 23 15:55:53 2011
@@ -26,7 +26,7 @@
/**
* Maps a named property to a Value.
*/
-public class CssProperty extends CssNode {
+public class CssProperty extends CssNode implements CssSubstitution {
/**
* Represents a sequence of no-arg method invocations.
@@ -77,6 +77,11 @@
public DotPathValue isDotPathValue() {
return this;
}
+
+ @Override
+ public boolean isStatic() {
+ return false;
+ }
@Override
public String toCss() {
@@ -104,6 +109,11 @@
public ExpressionValue isExpressionValue() {
return this;
}
+
+ @Override
+ public boolean isStatic() {
+ return false;
+ }
@Override
public String toCss() {
@@ -189,6 +199,19 @@
public ListValue isListValue() {
return this;
}
+
+ /**
+ * A ListValue is static if all of its component values are static.
+ */
+ @Override
+ public boolean isStatic() {
+ for (Value value : values) {
+ if (!value.isStatic()) {
+ return false;
+ }
+ }
+ return true;
+ }
@Override
public String toCss() {
@@ -381,6 +404,15 @@
public boolean isSpaceRequired() {
return true;
}
+
+ /**
+ * Indicates if the value is static.
+ *
+ * @see CssNode#isStatic()
+ */
+ public boolean isStatic() {
+ return true;
+ }
public StringValue isStringValue() {
return null;
@@ -423,6 +455,11 @@
public boolean isImportant() {
return important;
}
+
+ @Override
+ public boolean isStatic() {
+ return getValues().isStatic();
+ }
public void setImportant(boolean important) {
this.important = important;
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssRule.java Tue Mar
17 11:59:31 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssRule.java Wed Feb
23 15:55:53 2011
@@ -32,6 +32,11 @@
public List<CssSelector> getSelectors() {
return selectors;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
if (visitor.visit(this, context)) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssSelector.java Sat
Oct 10 13:50:44 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssSelector.java Wed
Feb 23 15:55:53 2011
@@ -36,6 +36,11 @@
public String getSelector() {
return selector;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void setSelector(String selector) {
this.selector = selector;
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssSprite.java Tue
Oct 5 11:03:13 2010
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssSprite.java Wed Feb
23 15:55:53 2011
@@ -30,7 +30,7 @@
* one well-known property {@value IMAGE_PROPERTY_NAME}, which
* specifies the name of an ImageResource accessor.
*/
-public class CssSprite extends CssRule {
+public class CssSprite extends CssRule implements CssSubstitution {
public static final String IMAGE_PROPERTY_NAME = "gwt-image";
@@ -169,6 +169,11 @@
public DotPathValue getResourceFunction() {
return resourceFunction;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void setResourceFunction(DotPathValue resourceFunction) {
this.resourceFunction = resourceFunction;
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssStylesheet.java Thu
Sep 2 06:12:48 2010
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssStylesheet.java Wed
Feb 23 15:55:53 2011
@@ -46,6 +46,11 @@
public List<CssNode> getNodes() {
return rules;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
if (visitor.visit(this, context)) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssUnknownAtRule.java
Thu Jan 21 09:47:21 2010
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssUnknownAtRule.java
Wed Feb 23 15:55:53 2011
@@ -32,6 +32,11 @@
public String getRule() {
return rule;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
public void traverse(CssVisitor visitor, Context context) {
if (visitor.visit(this, context)) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/css/ast/CssUrl.java Tue Dec 15
16:53:51 2009
+++ /trunk/user/src/com/google/gwt/resources/css/ast/CssUrl.java Wed Feb 23
15:55:53 2011
@@ -41,6 +41,11 @@
public List<Value> getValues() {
return values;
}
+
+ @Override
+ public boolean isStatic() {
+ return true;
+ }
@Override
public void traverse(CssVisitor visitor, Context context) {
=======================================
--- /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
Wed Feb 9 07:49:06 2011
+++ /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
Wed Feb 23 15:55:53 2011
@@ -57,13 +57,14 @@
import com.google.gwt.resources.css.ast.CssIf;
import com.google.gwt.resources.css.ast.CssNode;
import com.google.gwt.resources.css.ast.CssProperty;
-import com.google.gwt.resources.css.ast.CssRule;
-import com.google.gwt.resources.css.ast.CssStylesheet;
-import com.google.gwt.resources.css.ast.HasNodes;
import com.google.gwt.resources.css.ast.CssProperty.DotPathValue;
import com.google.gwt.resources.css.ast.CssProperty.ListValue;
import com.google.gwt.resources.css.ast.CssProperty.NumberValue;
import com.google.gwt.resources.css.ast.CssProperty.Value;
+import com.google.gwt.resources.css.ast.CssRule;
+import com.google.gwt.resources.css.ast.CssStylesheet;
+import com.google.gwt.resources.css.ast.CssSubstitution;
+import com.google.gwt.resources.css.ast.HasNodes;
import com.google.gwt.resources.ext.AbstractResourceGenerator;
import com.google.gwt.resources.ext.ClientBundleRequirements;
import com.google.gwt.resources.ext.ResourceContext;
@@ -74,6 +75,7 @@
import java.io.Serializable;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
@@ -89,7 +91,7 @@
/**
* Provides implementations of CSSResources.
*/
-public final class CssResourceGenerator extends AbstractResourceGenerator
+public class CssResourceGenerator extends AbstractResourceGenerator
implements SupportsGeneratorResultCaching {
@SuppressWarnings("serial")
@@ -266,7 +268,7 @@
int numExpressions = 0;
b.append('(');
- for (Map.Entry<Integer, List<CssNode>> entry :
v.getSubstitutionPositions().entrySet()) {
+ for (Map.Entry<Integer, List<CssSubstitution>> entry :
v.getSubstitutionPositions().entrySet()) {
// Add the static section between start and the substitution point
b.append('"');
b.append(Generator.escape(template.substring(start,
entry.getKey())));
@@ -274,7 +276,7 @@
numExpressions = concatOp(numExpressions, b);
// Add the nodes at the substitution point
- for (CssNode x : entry.getValue()) {
+ for (CssSubstitution x : entry.getValue()) {
TreeLogger loopLogger = logger.branch(TreeLogger.DEBUG,
"Performing substitution in node " + x.toString());
@@ -421,6 +423,8 @@
}
}
+ protected List<String> ignoredMethods = new ArrayList<String>();
+ protected Map<JMethod, CssStylesheet> stylesheetMap;
private Counter classCounter;
private JClassType cssResourceType;
private JClassType elementType;
@@ -429,7 +433,6 @@
private Map<JClassType, Map<JMethod, String>>
replacementsByClassAndMethod;
private Map<JMethod, String> replacementsForSharedMethods;
private JClassType stringType;
- private Map<JMethod, CssStylesheet> stylesheetMap;
@Override
public String createAssignment(TreeLogger logger, ResourceContext
context,
@@ -444,61 +447,29 @@
JClassType cssResourceSubtype = method.getReturnType().isInterface();
assert cssResourceSubtype != null;
- Map<String, Map<JMethod, String>> replacementsWithPrefix = new
HashMap<String, Map<JMethod, String>>();
-
- replacementsWithPrefix.put("",
- computeReplacementsForType(cssResourceSubtype));
- Import imp = method.getAnnotation(Import.class);
- if (imp != null) {
- boolean fail = false;
- for (Class<? extends CssResource> clazz : imp.value()) {
- JClassType importType =
typeOracle.findType(clazz.getName().replace(
- '$', '.'));
- assert importType != null : "TypeOracle does not have type "
- + clazz.getName();
-
- // add this import type as a requirement for this generator
- context.getRequirements().addTypeHierarchy(importType);
-
- String prefix = getImportPrefix(importType);
-
- if (replacementsWithPrefix.put(prefix,
- computeReplacementsForType(importType)) != null) {
- logger.log(TreeLogger.ERROR,
- "Multiple imports that would use the prefix " + prefix);
- fail = true;
- }
- }
- if (fail) {
- throw new UnableToCompleteException();
- }
- }
+
+ // Compute the local effective namespace
+ Map<String, Map<JMethod, String>> replacementsWithPrefix =
processImports(
+ logger, typeOracle, cssResourceSubtype, method, context);
// Methods defined by CssResource interface
writeEnsureInjected(sw);
writeGetName(method, sw);
-
- sw.println("public String getText() {");
- sw.indent();
- boolean strict = isStrict(logger, method);
- Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod,
String>();
- String cssExpression = makeExpression(logger, context,
cssResourceSubtype,
- stylesheetMap.get(method), replacementsWithPrefix, strict,
- actualReplacements);
- sw.println("return " + cssExpression + ";");
- sw.outdent();
- sw.println("}");
-
+
+ // Create the Java expression that generates the CSS
+ Map<JMethod, String> actualReplacements = writeGetText(logger, context,
+ method, sw, cssResourceSubtype, replacementsWithPrefix);
+
/*
* getOverridableMethods is used to handle CssResources extending
* non-CssResource types. See the discussion in
computeReplacementsForType.
*/
writeUserMethods(logger, sw, stylesheetMap.get(method),
cssResourceSubtype.getOverridableMethods(), actualReplacements);
-
+
sw.outdent();
sw.println("}");
-
+
return sw.toString();
}
@@ -533,20 +504,16 @@
throw new UnableToCompleteException();
}
- // Find all of the types that we care about in the type system
TypeOracle typeOracle = context.getGeneratorContext().getTypeOracle();
-
- cssResourceType = typeOracle.findType(CssResource.class.getName());
- assert cssResourceType != null;
-
- elementType = typeOracle.findType(Element.class.getName());
- assert elementType != null;
-
- stringType = typeOracle.findType(String.class.getName());
- assert stringType != null;
-
+ JClassType baseInterface = typeOracle.findType(getBaseInterfaceName());
+ for (JMethod m : baseInterface.getInheritableMethods()) {
+ ignoredMethods.add(m.getName());
+ }
+
+ // Find all of the types that we care about in the type system
+ checkTypes(context, typeOracle);
stylesheetMap = new IdentityHashMap<JMethod, CssStylesheet>();
-
+
initReplacements(logger, context, classPrefix);
}
@@ -571,7 +538,147 @@
// Create the AST and do a quick scan for requirements
CssStylesheet sheet = GenerateCssAst.exec(logger, resources);
stylesheetMap.put(method, sheet);
- (new RequirementsCollector(logger,
context.getRequirements())).accept(sheet);
+ (new RequirementsCollector(logger,
context.getRequirements())).accept(sheet);
+ }
+
+ protected void checkTypes(ResourceContext context, TypeOracle
typeOracle) {
+ cssResourceType = typeOracle.findType(CssResource.class.getName());
+ assert cssResourceType != null;
+
+ elementType = typeOracle.findType(Element.class.getName());
+ assert elementType != null;
+
+ stringType = typeOracle.findType(String.class.getName());
+ assert stringType != null;
+ }
+
+ protected String getBaseInterfaceName() {
+ return CssResource.class.getCanonicalName();
+ }
+
+ protected String makeExpressionForSheet(
+ TreeLogger logger, ResourceContext context, JClassType
cssResourceType,
+ CssStylesheet sheet, boolean prettyOutput) throws
UnableToCompleteException {
+ return makeExpression(logger, context, cssResourceType, sheet,
prettyOutput);
+ }
+
+ protected void optimize(TreeLogger logger, ResourceContext context,
+ JMethod method,
+ Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
+ Map<JMethod, String> actualReplacements) {
+ boolean strict = isStrict(logger, method);
+ CssStylesheet sheet = stylesheetMap.get(method);
+
+ // Create CSS sprites
+ (new Spriter(logger, context)).accept(sheet);
+
+ // Perform @def and @eval substitutions
+ SubstitutionCollector collector = new SubstitutionCollector();
+ collector.accept(sheet);
+
+ (new SubstitutionReplacer(logger, context,
collector.getSubstitutions()))
+ .accept(sheet);
+
+ // Evaluate @if statements based on deferred binding properties
+ (new IfEvaluator(logger,
+ context.getGeneratorContext().getPropertyOracle())).accept(sheet);
+
+ // Rename css .class selectors. We look for all @external declarations
in
+ // the stylesheet and then compute the per-instance replacements.
+ ExternalClassesCollector externalClasses = new
ExternalClassesCollector();
+ externalClasses.accept(sheet);
+ ClassRenamer renamer = new ClassRenamer(logger,
+ classReplacementsWithPrefix, strict, externalClasses.getClasses());
+ renamer.accept(sheet);
+ actualReplacements.putAll(renamer.getReplacements());
+
+ // Combine rules with identical selectors
+ if (enableMerge) {
+ (new SplitRulesVisitor()).accept(sheet);
+ (new MergeIdenticalSelectorsVisitor()).accept(sheet);
+ (new MergeRulesByContentVisitor()).accept(sheet);
+ }
+ }
+
+ /**
+ * Process the Import annotation on the associated JMethod and return a
map of
+ * prefixes to JMethods to locally obfuscated names.
+ */
+ protected Map<String, Map<JMethod, String>> processImports(TreeLogger
logger,
+ TypeOracle typeOracle, JClassType cssResourceSubtype, JMethod method,
+ ResourceContext context)
+ throws UnableToCompleteException {
+ Map<String, Map<JMethod, String>> replacementsWithPrefix =
+ new HashMap<String, Map<JMethod, String>>();
+
+ replacementsWithPrefix.put("",
+ computeReplacementsForType(cssResourceSubtype));
+ Import imp = method.getAnnotation(Import.class);
+ if (imp != null) {
+ boolean fail = false;
+ for (Class<? extends CssResource> clazz : imp.value()) {
+ JClassType importType =
typeOracle.findType(clazz.getName().replace(
+ '$', '.'));
+ assert importType != null : "TypeOracle does not have type "
+ + clazz.getName();
+
+ // add this import type as a requirement for this generator
+ context.getRequirements().addTypeHierarchy(importType);
+
+ String prefix = getImportPrefix(importType);
+
+ if (replacementsWithPrefix.put(prefix,
+ computeReplacementsForType(importType)) != null) {
+ logger.log(TreeLogger.ERROR,
+ "Multiple imports that would use the prefix " + prefix);
+ fail = true;
+ }
+ }
+ if (fail) {
+ throw new UnableToCompleteException();
+ }
+ }
+ return replacementsWithPrefix;
+ }
+
+ /**
+ * Write all of the user-defined methods in the CssResource subtype.
+ */
+ protected void writeUserMethods(TreeLogger logger, SourceWriter sw,
+ CssStylesheet sheet, JMethod[] methods,
+ Map<JMethod, String> obfuscatedClassNames)
+ throws UnableToCompleteException {
+
+ // Get list of @defs
+ DefsCollector collector = new DefsCollector();
+ collector.accept(sheet);
+ Set<String> defs = collector.getDefs();
+
+ for (JMethod toImplement : methods) {
+ String name = toImplement.getName();
+ if (ignoredMethods.contains(name)) {
+ continue;
+ }
+
+ // Bomb out if there is a collision between @def and a style name
+ if (defs.contains(name) &&
obfuscatedClassNames.containsKey(toImplement)) {
+ logger.log(TreeLogger.ERROR, "@def shadows CSS class name: " + name
+ + ". Fix by renaming the @def name or the CSS class name.");
+ throw new UnableToCompleteException();
+ }
+
+ if (defs.contains(toImplement.getName())
+ && toImplement.getParameters().length == 0) {
+ writeDefAssignment(logger, sw, toImplement, sheet);
+ } else if (toImplement.getReturnType().equals(stringType)
+ && toImplement.getParameters().length == 0) {
+ writeClassAssignment(sw, toImplement, obfuscatedClassNames);
+ } else {
+ logger.log(TreeLogger.ERROR, "Don't know how to implement method "
+ + toImplement.getName());
+ throw new UnableToCompleteException();
+ }
+ }
}
/**
@@ -632,8 +739,7 @@
for (JMethod method : type.getOverridableMethods()) {
String name = method.getName();
- if ("getName".equals(name) || "getText".equals(name)
- || !stringType.equals(method.getReturnType())) {
+ if (ignoredMethods.contains(name)) {
continue;
}
@@ -882,53 +988,25 @@
private String makeExpression(TreeLogger logger, ResourceContext context,
JClassType cssResourceType, CssStylesheet sheet,
Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
- boolean strict, Map<JMethod, String> actualReplacements)
+ JMethod method, Map<JMethod, String> actualReplacements)
throws UnableToCompleteException {
try {
-
- // Create CSS sprites
- (new Spriter(logger, context)).accept(sheet);
-
- // Perform @def and @eval substitutions
- SubstitutionCollector collector = new SubstitutionCollector();
- collector.accept(sheet);
-
- (new SubstitutionReplacer(logger, context,
collector.getSubstitutions())).accept(sheet);
-
- // Evaluate @if statements based on deferred binding properties
- (new IfEvaluator(logger,
-
context.getGeneratorContext().getPropertyOracle())).accept(sheet);
-
- /*
- * Rename css .class selectors. We look for all @external
declarations in
- * the stylesheet and then compute the per-instance replacements.
- */
- ExternalClassesCollector externalClasses = new
ExternalClassesCollector();
- externalClasses.accept(sheet);
- ClassRenamer renamer = new ClassRenamer(logger,
- classReplacementsWithPrefix, strict,
externalClasses.getClasses());
- renamer.accept(sheet);
- actualReplacements.putAll(renamer.getReplacements());
-
- // Combine rules with identical selectors
- if (enableMerge) {
- (new SplitRulesVisitor()).accept(sheet);
- (new MergeIdenticalSelectorsVisitor()).accept(sheet);
- (new MergeRulesByContentVisitor()).accept(sheet);
- }
-
- String standard = makeExpression(logger, context, cssResourceType,
sheet,
- prettyOutput);
-
+ optimize(logger, context, method, classReplacementsWithPrefix,
+ actualReplacements);
+
+ String standard = makeExpressionForSheet(logger, context,
cssResourceType,
+ sheet, prettyOutput);
(new RtlVisitor()).accept(sheet);
-
- String reversed = makeExpression(logger, context, cssResourceType,
sheet,
- prettyOutput);
-
- return LocaleInfo.class.getName() + ".getCurrentLocale().isRTL() ? ("
- + reversed + ") : (" + standard + ")";
-
+ String reversed = makeExpressionForSheet(logger, context,
cssResourceType,
+ sheet, prettyOutput);
+
+ if (standard.equals(reversed)) {
+ return standard;
+ } else {
+ return LocaleInfo.class.getName() + ".getCurrentLocale().isRTL() ?
("
+ + reversed + ") : (" + standard + ")";
+ }
} catch (CssCompilerException e) {
// Take this as a sign that one of the visitors was unhappy, but only
// log the stack trace if there's a causal (i.e. unknown) exception.
@@ -1037,44 +1115,20 @@
sw.println("}");
}
- /**
- * Write all of the user-defined methods in the CssResource subtype.
- */
- private void writeUserMethods(TreeLogger logger, SourceWriter sw,
- CssStylesheet sheet, JMethod[] methods,
- Map<JMethod, String> obfuscatedClassNames)
+ private Map<JMethod, String> writeGetText(TreeLogger logger,
+ ResourceContext context, JMethod method, SourceWriter sw,
+ JClassType cssResourceSubtype,
+ Map<String, Map<JMethod, String>> replacementsWithPrefix)
throws UnableToCompleteException {
-
- // Get list of @defs
- DefsCollector collector = new DefsCollector();
- collector.accept(sheet);
- Set<String> defs = collector.getDefs();
-
- for (JMethod toImplement : methods) {
- String name = toImplement.getName();
- if ("getName".equals(name) || "getText".equals(name)
- || "ensureInjected".equals(name)) {
- continue;
- }
-
- // Bomb out if there is a collision between @def and a style name
- if (defs.contains(name) &&
obfuscatedClassNames.containsKey(toImplement)) {
- logger.log(TreeLogger.ERROR, "@def shadows CSS class name: " + name
- + ". Fix by renaming the @def name or the CSS class name.");
- throw new UnableToCompleteException();
- }
-
- if (defs.contains(toImplement.getName())
- && toImplement.getParameters().length == 0) {
- writeDefAssignment(logger, sw, toImplement, sheet);
- } else if (toImplement.getReturnType().equals(stringType)
- && toImplement.getParameters().length == 0) {
- writeClassAssignment(sw, toImplement, obfuscatedClassNames);
- } else {
- logger.log(TreeLogger.ERROR, "Don't know how to implement method "
- + toImplement.getName());
- throw new UnableToCompleteException();
- }
- }
+ sw.println("public String getText() {");
+ sw.indent();
+ Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod,
String>();
+ String cssExpression = makeExpression(logger, context,
cssResourceSubtype,
+ stylesheetMap.get(method), replacementsWithPrefix, method,
+ actualReplacements);
+ sw.println("return " + cssExpression + ";");
+ sw.outdent();
+ sw.println("}");
+ return actualReplacements;
}
}
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors