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

Reply via email to