Author: [email protected]
Date: Wed May 20 16:14:31 2009
New Revision: 5449
Added:
trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
(contents, props changed)
Modified:
trunk/user/src/com/google/gwt/resources/client/CssResource.java
trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
trunk/user/src/com/google/gwt/resources/css/GenerateCssAst.java
trunk/user/src/com/google/gwt/resources/css/ast/CssNodeCloner.java
trunk/user/src/com/google/gwt/resources/css/ast/CssVisitor.java
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
trunk/user/test/com/google/gwt/resources/client/CSSResourceTest.java
trunk/user/test/com/google/gwt/resources/client/test.css
trunk/user/test/com/google/gwt/resources/client/unrelatedDescendants.css
Log:
Add an @external directive to CssResource to allow strict-mode resources to
work with external/legacy CSS.
Patch by: bobv
Review by: rjrjr
Modified: trunk/user/src/com/google/gwt/resources/client/CssResource.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/client/CssResource.java
(original)
+++ trunk/user/src/com/google/gwt/resources/client/CssResource.java Wed May
20 16:14:31 2009
@@ -47,6 +47,9 @@
* previously-defined rules, but no forward-references will be
honored.</li>
* <li>{...@code @eval NAME Java-expression; .myClass background: NAME;}
Define a
* constant based on a Java expression.</li>
+ * <li>{...@code @external class-name, class-name, ...;} Disable obfuscation
for
+ * specific class selectors and exclude those class selectors from
+ * {...@link Strict} requirements.</li>
* <li><code>{...@literal @if} [!]property list of values {ruleBlock}</code>
Include or
* exclude CSS rules based on the value of a deferred-binding property.
Also
* {...@code @elif} and {...@code @else} follow the same pattern.<br/>
@@ -219,11 +222,11 @@
/**
* The presence of this annotation on a CssResource accessor method
indicates
* that any class selectors that do not correspond with a String accessor
- * method in the return type should trigger a compilation error. In the
normal
- * case, any unobfuscatable class selectors will be emitted as-is. This
- * annotation ensures that the resource does not contribute any
unobfuscated
- * class selectors into the global CSS namespace and is recommended as
the
- * default for library-provided CssResource instances.
+ * method in the return type should trigger a compilation error. In the
+ * default case, any unobfuscatable class selectors will be emitted
as-is.
+ * This annotation ensures that the CssResource does not contribute any
+ * unobfuscated class selectors into the global CSS namespace and is
+ * recommended as the default behavior for CssResources.
* <p>
* Given these interfaces:
*
@@ -241,6 +244,26 @@
*
* the source CSS will fail to compile if it does not contain exactly
the one
* class selector defined in the MyCss type.
+ * <p>
+ * The {...@code @external} at-rule can be used in strict mode to indicate
that
+ * certain class selectors are exempt from the strict semantics. Class
+ * selectors marked as external will not be obfuscated and are not
required to
+ * have string accessor functions. Consider the following example in
+ * conjunction with the above <code>MyCss</code> interface:
+ *
+ * <pre>
+ * {...@literal @external} .foo, .bar;
+ * .foo .someClass .bar { .... }
+ * </pre>
+ *
+ * The resulting CSS would look like:
+ *
+ * <pre>
+ * .foo .A1234 .bar { .... }
+ * </pre>
+ *
+ * If a <code>String foo()</code> method were defined in
<code>MyCss</code>,
+ * it would return the string value "<code>foo</code>".
*/
@Documented
@Target(ElementType.METHOD)
Modified:
trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
(original)
+++ trunk/user/src/com/google/gwt/resources/css/CssGenerationVisitor.java
Wed May 20 16:14:31 2009
@@ -19,6 +19,7 @@
import com.google.gwt.resources.css.ast.Context;
import com.google.gwt.resources.css.ast.CssDef;
import com.google.gwt.resources.css.ast.CssEval;
+import com.google.gwt.resources.css.ast.CssExternalSelectors;
import com.google.gwt.resources.css.ast.CssIf;
import com.google.gwt.resources.css.ast.CssMediaRule;
import com.google.gwt.resources.css.ast.CssNoFlip;
@@ -124,6 +125,19 @@
public boolean visit(CssEval x, Context ctx) {
// These are not valid CSS
out.printOpt("/* CssEval */");
+ out.newlineOpt();
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssExternalSelectors x, Context ctx) {
+ // These are not valid CSS
+ out.printOpt("/* @external");
+ for (String className : x.getClasses()) {
+ out.printOpt(" ");
+ out.printOpt(className);
+ }
+ out.printOpt("; */");
out.newlineOpt();
return false;
}
Modified: trunk/user/src/com/google/gwt/resources/css/GenerateCssAst.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/css/GenerateCssAst.java
(original)
+++ trunk/user/src/com/google/gwt/resources/css/GenerateCssAst.java Wed May
20 16:14:31 2009
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.resources.css.ast.CssDef;
import com.google.gwt.resources.css.ast.CssEval;
+import com.google.gwt.resources.css.ast.CssExternalSelectors;
import com.google.gwt.resources.css.ast.CssIf;
import com.google.gwt.resources.css.ast.CssMediaRule;
import com.google.gwt.resources.css.ast.CssNoFlip;
@@ -71,6 +72,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -407,6 +409,16 @@
CssEval eval = new CssEval(parts[1], parts[2]);
addNode(eval);
+ }
+
+ void parseExternal(String atRule) throws CSSException {
+ // @external .foo, bar; Drop the dots and commas
+ String[] parts = atRule.substring(10, atRule.length() -
1).replaceAll(
+ "(, *)|( +)", " ").replaceAll("\\.", "").split(" ");
+
+ CssExternalSelectors externals = new CssExternalSelectors();
+ Collections.addAll(externals.getClasses(), parts);
+ addNode(externals);
}
void parseIf(String atRule) throws CSSException {
Added:
trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
==============================================================================
--- (empty file)
+++
trunk/user/src/com/google/gwt/resources/css/ast/CssExternalSelectors.java
Wed May 20 16:14:31 2009
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An AST node that allows the developer to indicate that certain class
+ * selectors appearing in the stylesheet should be considered external and
not
+ * subject to obfuscation requirements.
+ *
+ * @see CssResource.Strict
+ */
+public class CssExternalSelectors extends CssNode {
+
+ private final Set<String> classes = new HashSet<String>();
+
+ public Set<String> getClasses() {
+ return classes;
+ }
+
+ public void traverse(CssVisitor visitor, Context context) {
+ visitor.visit(this, context);
+ visitor.endVisit(this, context);
+ }
+
+}
Modified: trunk/user/src/com/google/gwt/resources/css/ast/CssNodeCloner.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/css/ast/CssNodeCloner.java
(original)
+++ trunk/user/src/com/google/gwt/resources/css/ast/CssNodeCloner.java Wed
May 20 16:14:31 2009
@@ -131,6 +131,14 @@
return true;
}
+ @Override
+ public boolean visit(CssExternalSelectors x, Context ctx) {
+ CssExternalSelectors newExternals = new CssExternalSelectors();
+ newExternals.getClasses().addAll(x.getClasses());
+ addToNodes(newExternals);
+ return true;
+ }
+
/**
* A CssIf has two lists of nodes, so we want to handle traversal in this
* visitor.
Modified: trunk/user/src/com/google/gwt/resources/css/ast/CssVisitor.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/css/ast/CssVisitor.java
(original)
+++ trunk/user/src/com/google/gwt/resources/css/ast/CssVisitor.java Wed May
20 16:14:31 2009
@@ -18,7 +18,10 @@
import java.util.List;
/**
- * The base class for visiting a CSS tree.
+ * The base class for visiting a CSS tree. Traversal is initiated with a
call to
+ * one of the <code>accept</code> methods. The default behavior of the
+ * <code>visit</code> methods is to return <code>true</code> to indicate
that
+ * the calling node should traverse its descendant nodes.
*/
public class CssVisitor {
protected static final Context UNMODIFIABLE_CONTEXT = new Context() {
@@ -66,6 +69,9 @@
public void endVisit(CssEval x, Context ctx) {
}
+ public void endVisit(CssExternalSelectors x, Context ctx) {
+ }
+
public void endVisit(CssIf x, Context ctx) {
}
@@ -101,6 +107,10 @@
}
public boolean visit(CssEval x, Context ctx) {
+ return true;
+ }
+
+ public boolean visit(CssExternalSelectors x, Context ctx) {
return true;
}
Modified:
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
==============================================================================
---
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
(original)
+++
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
Wed May 20 16:14:31 2009
@@ -268,7 +268,8 @@
try {
rhs = rg.createAssignment(logger.branch(TreeLogger.DEBUG,
- "Creating assignment for " + m.getName()), resourceContext, m);
+ "Creating assignment for " + m.getName() + "()"),
resourceContext,
+ m);
} catch (UnableToCompleteException e) {
fail = true;
continue;
Modified:
trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
(original)
+++ trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
Wed May 20 16:14:31 2009
@@ -31,6 +31,7 @@
import com.google.gwt.dev.util.DefaultTextOutput;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.DataResource;
import com.google.gwt.resources.client.ImageResource;
@@ -48,6 +49,7 @@
import com.google.gwt.resources.css.ast.CssCompilerException;
import com.google.gwt.resources.css.ast.CssDef;
import com.google.gwt.resources.css.ast.CssEval;
+import com.google.gwt.resources.css.ast.CssExternalSelectors;
import com.google.gwt.resources.css.ast.CssIf;
import com.google.gwt.resources.css.ast.CssMediaRule;
import com.google.gwt.resources.css.ast.CssModVisitor;
@@ -100,11 +102,19 @@
* Provides implementations of CSSResources.
*/
public class CssResourceGenerator extends AbstractResourceGenerator {
- private static final String[] DEFAULT_EXTENSIONS = new String[] {".css"};
-
static class ClassRenamer extends CssVisitor {
+ private final Map<JMethod, String> actualReplacements = new
IdentityHashMap<JMethod, String>();
+
+ /**
+ * This is a map of local prefixes to the obfuscated names of imported
+ * methods. If a CssResource makes use of the {...@link Import}
annotation, the
+ * keys of this map will correspond to the {...@link ImportedWithPrefix}
value
+ * defined on the imported CssResource. The zero-length string key
holds the
+ * obfuscated names for the CssResource that is being generated.
+ */
private final Map<String, Map<JMethod, String>>
classReplacementsWithPrefix;
private final Pattern classSelectorPattern =
Pattern.compile("\\.([^ :>+#.]*)");
+ private final Set<String> externalClasses;
private final TreeLogger logger;
private final Set<JMethod> missingClasses;
private final Set<String> replacedClasses = new HashSet<String>();
@@ -113,10 +123,11 @@
public ClassRenamer(TreeLogger logger,
Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
- boolean strict) {
+ boolean strict, Set<String> externalClasses) {
this.logger = logger.branch(TreeLogger.DEBUG, "Replacing CSS class
names");
this.classReplacementsWithPrefix = classReplacementsWithPrefix;
this.strict = strict;
+ this.externalClasses = externalClasses;
// Require a definition for all classes in the default namespace
assert classReplacementsWithPrefix.containsKey("");
@@ -132,22 +143,31 @@
for (Map.Entry<String, Map<JMethod, String>> outerEntry :
classReplacementsWithPrefix.entrySet()) {
String prefix = outerEntry.getKey();
for (Map.Entry<JMethod, String> entry :
outerEntry.getValue().entrySet()) {
- String name = entry.getKey().getName();
+ JMethod method = entry.getKey();
+ String sourceClassName = method.getName();
+ String obfuscatedClassName = entry.getValue();
- ClassName className =
entry.getKey().getAnnotation(ClassName.class);
+ ClassName className = method.getAnnotation(ClassName.class);
if (className != null) {
- name = className.value();
+ sourceClassName = className.value();
}
- name = prefix + name;
- Pattern p = Pattern.compile("(.*)\\.(" + Pattern.quote(name)
- + ")([ :>+#.].*|$)");
+ sourceClassName = prefix + sourceClassName;
+
+ Pattern p = Pattern.compile("(.*)\\.("
+ + Pattern.quote(sourceClassName) + ")([ :>+#.].*|$)");
Matcher m = p.matcher(sel);
if (m.find()) {
- sel = m.group(1) + "." + entry.getValue() + m.group(3);
- missingClasses.remove(entry.getKey());
+ if (externalClasses.contains(sourceClassName)) {
+ actualReplacements.put(method, sourceClassName);
+ } else {
+ sel = m.group(1) + "." + obfuscatedClassName + m.group(3);
+ actualReplacements.put(method, obfuscatedClassName);
+ }
+
+ missingClasses.remove(method);
if (strict) {
- replacedClasses.add(entry.getValue());
+ replacedClasses.add(obfuscatedClassName);
}
}
}
@@ -159,7 +179,8 @@
Matcher m = classSelectorPattern.matcher(sel);
while (m.find()) {
String classSelector = m.group(1);
- if (!replacedClasses.contains(classSelector)) {
+ if (!replacedClasses.contains(classSelector)
+ && !externalClasses.contains(classSelector)) {
unknownClasses.add(classSelector);
}
}
@@ -200,6 +221,26 @@
throw new CssCompilerException("Missing a CSS replacement");
}
}
+
+ public Map<JMethod, String> getReplacements() {
+ return actualReplacements;
+ }
+ }
+
+ /**
+ * Collects all {...@code @external} declarations in the stylesheet.
+ */
+ static class ExternalClassesCollector extends CssVisitor {
+ private final Set<String> classes = new HashSet<String>();
+
+ @Override
+ public void endVisit(CssExternalSelectors x, Context ctx) {
+ classes.addAll(x.getClasses());
+ }
+
+ public Set<String> getClasses() {
+ return classes;
+ }
}
/**
@@ -224,12 +265,11 @@
String propertyName = x.getPropertyName();
String propValue = null;
try {
- SelectionProperty selProp
- = oracle.getSelectionProperty(logger, propertyName);
+ SelectionProperty selProp = oracle.getSelectionProperty(logger,
+ propertyName);
propValue = selProp.getCurrentValue();
} catch (BadPropertyValueException e) {
- ConfigurationProperty confProp
- = oracle.getConfigurationProperty(propertyName);
+ ConfigurationProperty confProp =
oracle.getConfigurationProperty(propertyName);
propValue = confProp.getValues().get(0);
}
@@ -922,6 +962,8 @@
*/
private static final int CONCAT_EXPRESSION_LIMIT = 20;
+ private static final String[] DEFAULT_EXTENSIONS = new String[] {".css"};
+
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
System.out.println(makeIdent(i));
@@ -1158,11 +1200,8 @@
private boolean enableMerge;
private boolean prettyOutput;
private Map<JClassType, Map<JMethod, String>>
replacementsByClassAndMethod;
-
private Map<JMethod, String> replacementsForSharedMethods;
-
private Map<JMethod, CssStylesheet> stylesheetMap;
-
private JClassType stringType;
@Override
@@ -1206,57 +1245,13 @@
}
}
- /*
- * getOverridableMethods is used to handle CssResources extending
- * non-CssResource types. See the discussion in
computeReplacementsForType.
- */
- for (JMethod toImplement : cssResourceSubtype.getOverridableMethods())
{
- String name = toImplement.getName();
- if ("getName".equals(name) || "getText".equals(name)) {
- continue;
- }
-
- if (toImplement.getReturnType().equals(stringType)
- && toImplement.getParameters().length == 0) {
- writeClassAssignment(sw, toImplement,
replacementsWithPrefix.get(""));
-
- } else if (toImplement.getReturnType().isPrimitive() != null
- && toImplement.getParameters().length == 0) {
- writeDefAssignment(logger, sw, toImplement,
stylesheetMap.get(method));
-
- } else {
- logger.log(TreeLogger.ERROR, "Don't know how to implement method "
- + toImplement.getName());
- throw new UnableToCompleteException();
- }
- }
-
sw.println("public String getText() {");
sw.indent();
-
- boolean strict = method.getAnnotation(Strict.class) != null;
- if (!strict) {
- /*
- * The developer may choose to force strict behavior onto the
system. If
- * the method does already have the @Strict annotation, print a
warning.
- */
- try {
- PropertyOracle propertyOracle =
context.getGeneratorContext().getPropertyOracle();
- ConfigurationProperty prop =
propertyOracle.getConfigurationProperty(
- "CssResource.strictAccessors");
- String propertyValue = prop.getValues().get(0);
- if (Boolean.valueOf(propertyValue)) {
- logger.log(TreeLogger.WARN, "CssResource.forceStrict is true,
but "
- + method.getName() + "() is missing the @Strict
annotation.");
- strict = true;
- }
- } catch (BadPropertyValueException e) {
- // Ignore
- }
- }
-
+ boolean strict = isStrict(logger, context, method);
+ Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod,
String>();
String cssExpression = makeExpression(logger, context,
cssResourceSubtype,
- stylesheetMap.get(method), replacementsWithPrefix, strict);
+ stylesheetMap.get(method), replacementsWithPrefix, strict,
+ actualReplacements);
sw.println("return " + cssExpression + ";");
sw.outdent();
sw.println("}");
@@ -1267,6 +1262,13 @@
sw.outdent();
sw.println("}");
+ /*
+ * 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("}");
@@ -1278,19 +1280,15 @@
throws UnableToCompleteException {
try {
PropertyOracle propertyOracle =
context.getGeneratorContext().getPropertyOracle();
- ConfigurationProperty styleProp
- = propertyOracle.getConfigurationProperty("CssResource.style");
+ ConfigurationProperty styleProp =
propertyOracle.getConfigurationProperty("CssResource.style");
String style = styleProp.getValues().get(0);
prettyOutput = style.equals("pretty");
- ConfigurationProperty mergeProp
- =
propertyOracle.getConfigurationProperty("CssResource.mergeEnabled");
+ ConfigurationProperty mergeProp =
propertyOracle.getConfigurationProperty("CssResource.mergeEnabled");
String merge = mergeProp.getValues().get(0);
enableMerge = merge.equals("true");
- ConfigurationProperty classPrefixProp
- = propertyOracle.getConfigurationProperty(
- "CssResource.obfuscationPrefix");
+ ConfigurationProperty classPrefixProp =
propertyOracle.getConfigurationProperty("CssResource.obfuscationPrefix");
classPrefix = classPrefixProp.getValues().get(0);
} catch (BadPropertyValueException e) {
logger.log(TreeLogger.WARN, "Unable to query module property", e);
@@ -1504,14 +1502,46 @@
return false;
}
+ private boolean isStrict(TreeLogger logger, ResourceContext context,
+ JMethod method) {
+ boolean strict = method.getAnnotation(Strict.class) != null;
+ if (!strict) {
+ /*
+ * The developer may choose to force strict behavior onto the
system. If
+ * the method does not already have an @Strict annotation, print a
+ * warning.
+ */
+ try {
+ PropertyOracle propertyOracle =
context.getGeneratorContext().getPropertyOracle();
+ ConfigurationProperty prop =
propertyOracle.getConfigurationProperty("CssResource.strictAccessors");
+ String propertyValue = prop.getValues().get(0);
+ if (Boolean.valueOf(propertyValue)) {
+ logger.log(TreeLogger.WARN,
+ "CssResource.strictAccessors is true, but " +
method.getName()
+ + "() is missing the @Strict annotation.");
+ strict = true;
+ }
+ } catch (BadPropertyValueException e) {
+ // Ignore
+ }
+ }
+ return strict;
+ }
+
/**
* Create a Java expression that evaluates to the string representation
of the
* stylesheet resource.
+ *
+ * @param actualReplacements An out parameter that will be populated by
the
+ * obfuscated class names that should be used for the particular
+ * instance of the CssResource, based on any substitution
+ * modifications encoded in the source CSS file
*/
private String makeExpression(TreeLogger logger, ResourceContext context,
JClassType cssResourceType, CssStylesheet sheet,
Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
- boolean strict) throws UnableToCompleteException {
+ boolean strict, Map<JMethod, String> actualReplacements)
+ throws UnableToCompleteException {
try {
@@ -1528,12 +1558,19 @@
(new IfEvaluator(logger,
context.getGeneratorContext().getPropertyOracle())).accept(sheet);
- // Rename css .class selectors
- (new ClassRenamer(logger, classReplacementsWithPrefix,
strict)).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) {
- // TODO This is an off-switch while this is being developed; remove
(new SplitRulesVisitor()).accept(sheet);
(new MergeIdenticalSelectorsVisitor()).accept(sheet);
(new MergeRulesByContentVisitor()).accept(sheet);
@@ -1547,7 +1584,7 @@
String reversed = makeExpression(logger, context, cssResourceType,
sheet,
prettyOutput);
-
return "com.google.gwt.i18n.client.LocaleInfo.getCurrentLocale().isRTL() ?
("
+ return LocaleInfo.class.getName() + ".getCurrentLocale().isRTL() ? ("
+ reversed + ") : (" + standard + ")";
} catch (CssCompilerException e) {
@@ -1628,5 +1665,34 @@
sw.println("}");
numberValue.getValue();
+ }
+
+ /**
+ * 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)
+ throws UnableToCompleteException {
+ for (JMethod toImplement : methods) {
+ String name = toImplement.getName();
+ if ("getName".equals(name) || "getText".equals(name)) {
+ continue;
+ }
+
+ if (toImplement.getReturnType().equals(stringType)
+ && toImplement.getParameters().length == 0) {
+ writeClassAssignment(sw, toImplement, obfuscatedClassNames);
+
+ } else if (toImplement.getReturnType().isPrimitive() != null
+ && toImplement.getParameters().length == 0) {
+ writeDefAssignment(logger, sw, toImplement, sheet);
+
+ } else {
+ logger.log(TreeLogger.ERROR, "Don't know how to implement method "
+ + toImplement.getName());
+ throw new UnableToCompleteException();
+ }
+ }
}
}
Modified:
trunk/user/test/com/google/gwt/resources/client/CSSResourceTest.java
==============================================================================
--- trunk/user/test/com/google/gwt/resources/client/CSSResourceTest.java
(original)
+++ trunk/user/test/com/google/gwt/resources/client/CSSResourceTest.java
Wed May 20 16:14:31 2009
@@ -23,7 +23,7 @@
import com.google.gwt.resources.client.CssResource.Strict;
/**
- *
+ * Contains various full-stack tests of the CssResource system.
*/
public class CSSResourceTest extends GWTTestCase {
@@ -48,6 +48,10 @@
int rawInt();
}
+ interface HasDescendants extends CssResource {
+ String foo();
+ }
+
interface MyCssResource extends CssResource, MyNonCssResource {
@ClassName("replacement-not-java-ident")
String nameOverride();
@@ -71,6 +75,8 @@
* Check type inheritance.
*/
interface MyCssResourceWithSprite extends MyCssResource {
+ String externalA();
+
String extraSpriteClass();
String multiClassA();
@@ -105,7 +111,7 @@
@Source("unrelatedDescendants.css")
@Import(value = {MyCssResourceA.class, MyCssResourceB.class})
@Strict
- CssResource descendants();
+ HasDescendants descendants();
@Source("16x16.png")
ImageResource spriteMethod();
@@ -223,6 +229,12 @@
// Check commonly-used CSS3 constructs
assertTrue(text.contains("background-color:rgba(0,0,0,0.5);"));
+
+ // Check external references
+ assertEquals("externalA", css.externalA());
+ assertTrue(text.contains(".externalA ." + css.replacement()));
+ assertTrue(text.contains(".externalB"));
+ assertTrue(text.contains(".externalC"));
}
public void testDefines() {
@@ -254,7 +266,10 @@
String text = r1.descendants().getText();
report(text);
+ assertEquals("foo", r1.descendants().foo());
assertTrue(text.contains("." + r1.a().local() + " ." +
r1.b().local()));
+ assertTrue(text.contains("." + r1.descendants().foo()));
+ assertTrue(text.contains(".bar"));
}
public void testSiblingCSS() {
Modified: trunk/user/test/com/google/gwt/resources/client/test.css
==============================================================================
--- trunk/user/test/com/google/gwt/resources/client/test.css (original)
+++ trunk/user/test/com/google/gwt/resources/client/test.css Wed May 20
16:14:31 2009
@@ -208,3 +208,7 @@
.css3Color {
background-color: rgba(0, 0, 0, 0.5);
}
+
+/* The @external parser attempts to be flexible */
+...@external externalA, .externalB externalC;
+.externalA .replacement, .externalB, .externalC {border: GREEN;}
Modified:
trunk/user/test/com/google/gwt/resources/client/unrelatedDescendants.css
==============================================================================
---
trunk/user/test/com/google/gwt/resources/client/unrelatedDescendants.css
(original)
+++
trunk/user/test/com/google/gwt/resources/client/unrelatedDescendants.css
Wed May 20 16:14:31 2009
@@ -18,3 +18,9 @@
.MyCssResourceA-local .gwt-MyCssResourceB-local {
background: green;
}
+
+/* These selectors are not to be obfuscated */
+...@external .foo, bar;
+.foo, .bar {
+ background: red;
+}
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---