Add GSS support in UiBinder.
Third patch concerning the support of GSS in GWT. This patch
introduces a new attribute named useGss that you can use
in order to enable GSS in the inline style of UiBinder
Change-Id: I7e6f907c3ffa4a4c8f642786506de2f9c4107e85
diff --git a/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java b/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java
new file mode 100644
index 0000000..610ef26
--- /dev/null
+++ b/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 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.gss;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.resources.rg.GssResourceGenerator;
+import com.google.gwt.thirdparty.common.css.compiler.ast.CssClassSelectorNode;
+import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree;
+import com.google.gwt.thirdparty.common.css.compiler.ast.DefaultTreeVisitor;
+import com.google.gwt.thirdparty.guava.common.base.Preconditions;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Collect all CSS class names in a stylesheet.
+ */
+public class ClassNamesCollector extends DefaultTreeVisitor {
+ private Set<String> classNames;
+ private SortedSet<String> excludedPrefixes;
+
+ /**
+ * Extract all CSS class names in the provided stylesheet, modulo those
+ * imported from another context.
+ */
+ public Set<String> getClassNames(CssTree tree, Set<JClassType> imports) {
+ Preconditions.checkNotNull(tree, "tree cannot be null");
+ Preconditions.checkNotNull(imports, "imports set cannot be null");
+
+ classNames = new HashSet<String>();
+ excludedPrefixes = new TreeSet<String>();
+
+ for (JClassType importedType : imports) {
+ excludedPrefixes.add(GssResourceGenerator.getImportPrefix(importedType));
+ }
+
+ tree.getVisitController().startVisit(this);
+
+ return classNames;
+ }
+
+ @Override
+ public boolean enterClassSelector(CssClassSelectorNode classSelector) {
+ String className = classSelector.getRefinerName();
+
+ if (!isImportedClass(className)) {
+ classNames.add(className);
+ }
+
+ return false;
+ }
+
+ private boolean isImportedClass(String className) {
+ SortedSet<String> lowerPrefixes = excludedPrefixes.headSet(className);
+
+ return !lowerPrefixes.isEmpty() && className.startsWith(lowerPrefixes.last());
+ }
+}
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index 8206f98..ecf6c3c 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -539,6 +539,9 @@
throw new UnableToCompleteException();
}
+ // At this point, gss is not enabled so we shouldn't try to compile a gss file.
+ ensureNoGssFile(resources, logger);
+
// Create the AST and do a quick scan for requirements
CssStylesheet sheet = GenerateCssAst.exec(logger, resources);
checkSheet(logger, sheet);
@@ -546,6 +549,19 @@
(new RequirementsCollector(logger, context.getRequirements())).accept(sheet);
}
+ private void ensureNoGssFile(URL[] resources, TreeLogger logger)
+ throws UnableToCompleteException {
+
+ for (URL stylesheet : resources) {
+ if (stylesheet.getFile().endsWith(".gss")) {
+ logger.log(Type.ERROR, "GSS is not enabled. Add the following line to your gwt.xml file " +
+ "to enable it: " +
+ "<set-configuration-property name=\"CssResource.enableGss\" value=\"true\" />");
+ throw new UnableToCompleteException();
+ }
+ }
+ }
+
protected void checkSheet(TreeLogger logger, CssStylesheet stylesheet)
throws UnableToCompleteException {
// Do nothing
diff --git a/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java
index 8093068..5c9f088 100644
--- a/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java
@@ -243,6 +243,19 @@
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', '0', '1',
'2', '3', '4', '5', '6'};
+ /**
+ * Returns the import prefix for a type, including the trailing hyphen.
+ */
+ public static String getImportPrefix(JClassType importType) {
+ String prefix = importType.getSimpleSourceName();
+ ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class);
+ if (exp != null) {
+ prefix = exp.value();
+ }
+
+ return prefix + "-";
+ }
+
private static String encode(long id) {
assert id >= 0;
@@ -1106,7 +1119,7 @@
// This substitution map will prefix each renamed class with the resource prefix and use a
// MinimalSubstitutionMap for computing the obfuscated name.
SubstitutionMap prefixingSubstitutionMap = new PrefixingSubstitutionMap(
- new MinimalSubstitutionMap(), obfuscationPrefix + resourcePrefix + "_");
+ new MinimalSubstitutionMap(), obfuscationPrefix + resourcePrefix + "-");
for (JMethod method : cssResource.getOverridableMethods()) {
if (method == getNameMethod || method == getTextMethod || method == ensuredInjectedMethod) {
@@ -1139,17 +1152,4 @@
replacementsForSharedMethods.put(method, obfuscatedClassName);
}
}
-
- /**
- * Returns the import prefix for a type, including the trailing hyphen.
- */
- private String getImportPrefix(JClassType importType) {
- String prefix = importType.getSimpleSourceName();
- ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class);
- if (exp != null) {
- prefix = exp.value();
- }
-
- return prefix + "-";
- }
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index c1cd78b..b7e16ca 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -92,6 +92,7 @@
private static final String REPEAT_STYLE_ATTRIBUTE = "repeatStyle";
private static final String SOURCE_ATTRIBUTE = "src";
private static final String TYPE_ATTRIBUTE = "type";
+ private static final String GSS_ATTRIBUTE = "gss";
// TODO(rjrjr) Make all the ElementParsers receive their dependencies via
// constructor like this one does, and make this an ElementParser. I want
@@ -445,8 +446,10 @@
importTypes.add(findCssResourceType(elem, type));
}
+ Boolean gss = elem.consumeBooleanConstantAttribute(GSS_ATTRIBUTE);
+
ImplicitCssResource cssMethod = bundleClass.createCssResource(name, source,
- publicType, body, importTypes, resourceOracle);
+ publicType, body, importTypes, gss, resourceOracle);
FieldWriter field = fieldManager.registerFieldForGeneratedCssResource(cssMethod);
field.setInitializer(String.format("%s.%s()",
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
index 3e98c33..e1afec8 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
@@ -63,14 +63,15 @@
* @param body the inline css text
* @param importTypes for the {@literal @}Import annotation, if any. LinkedHashSet
* to enforce deterministic order across recompiles
+ * @param gss indicates that GSS is used or not
* @param resourceOracle from which to load resources
* @return the newly-created CssResource
*/
public ImplicitCssResource createCssResource(String name, String[] source,
JClassType extendedInterface, String body, LinkedHashSet<JClassType> importTypes,
- ResourceOracle resourceOracle) {
+ Boolean gss, ResourceOracle resourceOracle) {
ImplicitCssResource css = new ImplicitCssResource(packageName, cssBaseName + name, name, source,
- extendedInterface, body, logger, importTypes, resourceOracle);
+ extendedInterface, body, logger, importTypes, gss, resourceOracle);
cssMethods.add(css);
return css;
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
index e3012ec..df4b742 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.uibinder.rebind.model;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.impl.ResourceLocatorImpl;
import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -23,6 +24,11 @@
import com.google.gwt.resources.css.GenerateCssAst;
import com.google.gwt.resources.css.ast.CssStylesheet;
import com.google.gwt.resources.ext.ResourceGeneratorUtil;
+import com.google.gwt.resources.gss.ClassNamesCollector;
+import com.google.gwt.thirdparty.common.css.SourceCode;
+import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree;
+import com.google.gwt.thirdparty.common.css.compiler.ast.GssParser;
+import com.google.gwt.thirdparty.common.css.compiler.ast.GssParserException;
import com.google.gwt.uibinder.attributeparsers.CssNameConverter;
import com.google.gwt.uibinder.rebind.MortalLogger;
@@ -55,6 +61,7 @@
private final MortalLogger logger;
private final Set<JClassType> imports;
private final ResourceOracle resourceOracle;
+ private final boolean gss;
private File generatedFile;
private Set<String> cssClassNames;
@@ -65,7 +72,8 @@
*/
public ImplicitCssResource(String packageName, String className, String name,
String[] source, JClassType extendedInterface, String body,
- MortalLogger logger, Set<JClassType> importTypes, ResourceOracle resourceOracle) {
+ MortalLogger logger, Set<JClassType> importTypes, Boolean gss,
+ ResourceOracle resourceOracle) {
this.packageName = packageName;
this.className = className;
this.name = name;
@@ -74,6 +82,7 @@
this.logger = logger;
this.imports = Collections.unmodifiableSet(importTypes);
this.resourceOracle = resourceOracle;
+ this.gss = Boolean.TRUE.equals(gss);
sources = Arrays.asList(source);
}
@@ -85,9 +94,9 @@
}
/**
- * Returns the set of CSS classnames in the underlying .css files.
+ * Returns the set of CSS classnames in the underlying css or gss files.
*
- * @throws UnableToCompleteException if the user has called for a .css file we
+ * @throws UnableToCompleteException if the user has called for a css/gss file we
* can't find.
*/
public Set<String> getCssClassNames() throws UnableToCompleteException {
@@ -103,10 +112,23 @@
}
assert urls.size() > 0;
- CssStylesheet sheet = GenerateCssAst.exec(logger.getTreeLogger(),
- urls.toArray(new URL[urls.size()]));
- cssClassNames = ExtractClassNamesVisitor.exec(sheet,
- imports.toArray(new JClassType[imports.size()]));
+ if (gss) {
+ SourceCode sourceCode = new SourceCode(bodyFile.getName(), body);
+ CssTree tree;
+ try {
+ tree = new GssParser(sourceCode).parse();
+ } catch (GssParserException e) {
+ logger.getTreeLogger().log(TreeLogger.ERROR, "Unable to parse CSS", e);
+ throw new UnableToCompleteException();
+ }
+ cssClassNames = new ClassNamesCollector().getClassNames(tree, imports);
+
+ } else {
+ CssStylesheet sheet = GenerateCssAst.exec(logger.getTreeLogger(),
+ urls.toArray(new URL[urls.size()]));
+ cssClassNames = ExtractClassNamesVisitor.exec(sheet,
+ imports.toArray(new JClassType[imports.size()]));
+ }
}
return cssClassNames;
}
@@ -168,7 +190,7 @@
}
/**
- * Returns the name of the .css file(s), separate by white space.
+ * Returns the name of the css or gss file(s), separate by white space.
*/
public Collection<String> getSource() {
if (body.length() == 0) {
@@ -181,7 +203,8 @@
}
private String getBodyFileName() {
- String bodyFileName = String.format("uibinder.%s.%s.css", packageName, className);
+ String bodyFileName = String.format("uibinder.%s.%s.%s", packageName, className,
+ getCssFileExtension());
// To verify that the resulting file can be retrieved out of zip files using a URL reference.
assert isValidUrl("file:/" + bodyFileName);
return bodyFileName;
@@ -225,8 +248,8 @@
if (generatedFile == null) {
try {
- File f = File.createTempFile(String.format("uiBinder_%s_%s",
- packageName, className), ".css");
+ File f = File.createTempFile(String.format("uiBinder_%s_%s", packageName, className),
+ "." + getCssFileExtension());
f.deleteOnExit();
BufferedWriter out = new BufferedWriter(new FileWriter(f));
@@ -251,4 +274,8 @@
}
return true;
}
+
+ private String getCssFileExtension() {
+ return gss ? "gss" : "css";
+ }
}
diff --git a/user/test/com/google/gwt/resources/ResourcesJreSuite.java b/user/test/com/google/gwt/resources/ResourcesJreSuite.java
index 3cd9dac..0fef2d5 100644
--- a/user/test/com/google/gwt/resources/ResourcesJreSuite.java
+++ b/user/test/com/google/gwt/resources/ResourcesJreSuite.java
@@ -28,6 +28,7 @@
import com.google.gwt.resources.css.ExtractClassNamesVisitorTest;
import com.google.gwt.resources.css.UnknownAtRuleTest;
import com.google.gwt.resources.ext.ResourceGeneratorUtilTest;
+import com.google.gwt.resources.gss.ClassNamesCollectorTest;
import com.google.gwt.resources.gss.CssPrinterTest;
import com.google.gwt.resources.gss.ExtendedEliminateConditionalNodesTest;
import com.google.gwt.resources.gss.ExternalClassesCollectorTest;
@@ -64,6 +65,8 @@
// GSS tests
suite.addTestSuite(ExternalClassesCollectorTest.class);
suite.addTestSuite(RenamingSubstitutionMapTest.class);
+ suite.addTestSuite(ImageSpriteCreatorTest.class);
+ suite.addTestSuite(ClassNamesCollectorTest.class);
suite.addTestSuite(CssPrinterTest.class);
suite.addTestSuite(PermutationsCollectorTest.class);
suite.addTestSuite(RecordingBidiFlipperTest.class);
@@ -74,7 +77,6 @@
suite.addTestSuite(RuntimeConditionalBlockCollectorTest.class);
suite.addTestSuite(ValidateRuntimeConditionalNodeTest.class);
suite.addTestSuite(ValueFunctionTest.class);
- suite.addTestSuite(ImageSpriteCreatorTest.class);
// CSS to GSS converter tests
suite.addTestSuite(Css2GssTest.class);
diff --git a/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java b/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java
new file mode 100644
index 0000000..ca24695
--- /dev/null
+++ b/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2014 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.gss;
+
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.resources.client.CssResource.ImportedWithPrefix;
+import com.google.gwt.thirdparty.common.css.compiler.ast.CssClassSelectorNode;
+import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree;
+import com.google.gwt.thirdparty.common.css.compiler.ast.VisitController;
+
+import junit.framework.TestCase;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test for {@link ClassNamesCollector}.
+ */
+public class ClassNamesCollectorTest extends TestCase {
+ private CssClassSelectorNode cssClassSelectorNode;
+ private CssTree cssTree;
+ private VisitController visitController;
+ private ClassNamesCollector classNamesCollector;
+
+ @Override
+ protected void setUp() {
+ classNamesCollector = new ClassNamesCollector();
+ cssClassSelectorNode = mock(CssClassSelectorNode.class);
+ cssTree = mock(CssTree.class);
+ visitController = mock(VisitController.class);
+
+ when(cssTree.getVisitController()).thenReturn(visitController);
+ }
+
+ public void testGetClassNames_noImport_collectAllClasses() {
+ // Given
+ List<CssClassSelectorNode> classSelectorNodes = createClassSelectorNodes("class1", "class2",
+ "class3");
+ whenVisitorControllerVisitTreeThenVisitAllNodes(classSelectorNodes);
+
+ // When
+ Set<String> classNames = classNamesCollector.getClassNames(cssTree, new HashSet<JClassType>());
+
+ // Then
+ assertEquals(3, classNames.size());
+ assertTrue(classNames.contains("class1"));
+ assertTrue(classNames.contains("class2"));
+ assertTrue(classNames.contains("class3"));
+ }
+
+ public void testGetClassNames_withImport_dontCollectImportedClasses() {
+ // Given
+ List<CssClassSelectorNode> classSelectorNodes = createClassSelectorNodes("class1", "class2",
+ "class3", "Imported-class", "ImportedFakeClass", "otherImport-class");
+ whenVisitorControllerVisitTreeThenVisitAllNodes(classSelectorNodes);
+
+ Set<JClassType> importedType = new HashSet<JClassType>();
+
+ // mock a class without @ImportedWithPrefix annotation
+ JClassType importedClassType = mock(JClassType.class);
+ when(importedClassType.getSimpleSourceName()).thenReturn("Imported");
+ importedType.add(importedClassType);
+
+ // mock a class with a @ImportedWithPrefix annotation
+ JClassType importedWithPrefixClassType = mock(JClassType.class);
+ when(importedWithPrefixClassType.getSimpleSourceName()).thenReturn("ImportedWithPrefix");
+ ImportedWithPrefix importedWithPrefixAnnotation = mock(ImportedWithPrefix.class);
+ when(importedWithPrefixAnnotation.value()).thenReturn("otherImport");
+ when(importedWithPrefixClassType.getAnnotation(ImportedWithPrefix.class))
+ .thenReturn(importedWithPrefixAnnotation);
+ importedType.add(importedWithPrefixClassType);
+
+ // When
+ Set<String> classNames = classNamesCollector.getClassNames(cssTree, importedType);
+
+ // Then
+ assertEquals(4, classNames.size());
+ assertTrue(classNames.contains("class1"));
+ assertTrue(classNames.contains("class2"));
+ assertTrue(classNames.contains("class3"));
+ assertTrue(classNames.contains("ImportedFakeClass"));
+ assertFalse(classNames.contains("otherImport-class"));
+ assertFalse(classNames.contains("Imported-class"));
+ }
+
+ private List<CssClassSelectorNode> createClassSelectorNodes(String... classNames) {
+ List<CssClassSelectorNode> classSelectorNodes = new ArrayList<CssClassSelectorNode>(classNames
+ .length);
+
+ for (String className : classNames) {
+ CssClassSelectorNode node = mock(CssClassSelectorNode.class);
+ when(node.getRefinerName()).thenReturn(className);
+ classSelectorNodes.add(node);
+ }
+
+ return classSelectorNodes;
+ }
+
+ private void whenVisitorControllerVisitTreeThenVisitAllNodes(final List<CssClassSelectorNode>
+ nodes) {
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ for (CssClassSelectorNode node : nodes) {
+ classNamesCollector.enterClassSelector(node);
+ }
+ return null;
+ }
+ }).when(visitController).startVisit(classNamesCollector);
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/UiBinderSuite.java b/user/test/com/google/gwt/uibinder/UiBinderSuite.java
index 0657bc1..110ed3c 100644
--- a/user/test/com/google/gwt/uibinder/UiBinderSuite.java
+++ b/user/test/com/google/gwt/uibinder/UiBinderSuite.java
@@ -23,6 +23,7 @@
import com.google.gwt.uibinder.test.client.UiBinderTest;
import com.google.gwt.uibinder.test.client.UiChildTest;
import com.google.gwt.uibinder.test.client.UiHandlerTest;
+import com.google.gwt.uibinder.test.client.gss.UiBinderWithGssTest;
import junit.framework.Test;
@@ -41,6 +42,7 @@
suite.addTestSuite(UiBinderUtilTest.class);
suite.addTestSuite(UiChildTest.class);
suite.addTestSuite(UiHandlerTest.class);
+ suite.addTestSuite(UiBinderWithGssTest.class);
return suite;
}
diff --git a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
index eae9c83..a76923f 100644
--- a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
@@ -58,7 +58,8 @@
ImplicitCssResource css = new ImplicitCssResource("package", "ClassName",
"fieldName", new String[] {}, cssResourceType, ".able-baker {}",
- MortalLogger.NULL, Collections.<JClassType> emptySet(), new MockResourceOracle());
+ MortalLogger.NULL, Collections.<JClassType> emptySet(), false,
+ new MockResourceOracle());
FieldWriterOfGeneratedCssResource f = new FieldWriterOfGeneratedCssResource(
null, stringType, css, MortalLogger.NULL);
@@ -74,7 +75,7 @@
ImplicitCssResource css = new ImplicitCssResource("package", "ClassName",
"fieldName", new String[] {}, cssResourceType, ".ableBaker {}",
- MortalLogger.NULL, Collections.<JClassType> emptySet(), new MockResourceOracle());
+ MortalLogger.NULL, Collections.<JClassType> emptySet(), false, new MockResourceOracle());
FieldWriterOfGeneratedCssResource f = new FieldWriterOfGeneratedCssResource(
null, stringType, css, MortalLogger.NULL);
diff --git a/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml b/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml
new file mode 100644
index 0000000..f7ccadf
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml
@@ -0,0 +1,8 @@
+<module type="fileset">
+ <inherits name="com.google.gwt.user.User" />
+ <inherits name="com.google.gwt.debug.Debug"/>
+ <inherits name="com.google.gwt.junit.JUnit"/>
+
+ <set-configuration-property name="CssResource.enableGss" value="true" />
+ <set-configuration-property name="CssResource.legacy" value="true" />
+</module>
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java b/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java
new file mode 100644
index 0000000..3b2f39f
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 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.uibinder.test.client.gss;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.CssStyle;
+import com.google.gwt.uibinder.test.client.gss.WidgetUsingGss.GssStyle;
+import com.google.gwt.user.client.ui.RootPanel;
+
+/**
+ * Test case for GSS integration in UiBinder.
+ */
+public class UiBinderWithGssTest extends GWTTestCase {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.uibinder.test.UiBinderWithGss";
+ }
+
+ public void testGssIntegration() {
+ WidgetUsingGss widgetUsingGss = new WidgetUsingGss();
+ GssStyle style = widgetUsingGss.style;
+ RootPanel.get().add(widgetUsingGss);
+
+ assertEquals(style.main(), widgetUsingGss.getStyleName());
+ String expectedCss = "." + style.main() + "{background-color:black;color:white;width:200px;" +
+ "height:300px}";
+ assertEquals(expectedCss, widgetUsingGss.style.getText());
+ }
+
+ public void testCssConversion() {
+ WidgetUsingCss widgetUsingCss = new WidgetUsingCss();
+ CssStyle style = widgetUsingCss.style;
+ RootPanel.get().add(widgetUsingCss);
+
+ assertEquals(style.main(), widgetUsingCss.getStyleName());
+ String expectedCss = "." + style.main() + "{background-color:black;color:white}";
+ assertEquals(expectedCss, widgetUsingCss.style.getText());
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java
new file mode 100644
index 0000000..52d5691
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 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.uibinder.test.client.gss;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Widget not using GSS syntax in the inline style of its UiBinder template.
+ */
+public class WidgetUsingCss extends Composite {
+ interface WidgetUsingCssUiBinder extends UiBinder<Widget, WidgetUsingCss> {
+ }
+
+ interface CssStyle extends CssResource {
+ String main();
+ }
+
+ static final String WHITE = "white";
+
+ private static WidgetUsingCssUiBinder uiBinder = GWT.create(WidgetUsingCssUiBinder.class);
+
+ @UiField
+ CssStyle style;
+
+ public WidgetUsingCss() {
+ initWidget(uiBinder.createAndBindUi(this));
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml
new file mode 100644
index 0000000..a3c973d
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml
@@ -0,0 +1,13 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+ <ui:style type="com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.CssStyle">
+ @def my_black black;
+ @eval my_white com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.WHITE;
+
+ .main {
+ background-color: my_black;
+ color: my_white;
+ }
+ </ui:style>
+ <g:SimplePanel styleName="{style.main}"/>
+</ui:UiBinder>
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java
new file mode 100644
index 0000000..35e941f
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 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.uibinder.test.client.gss;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Widget using GSS syntax in the inline style of its UiBinder template.
+ */
+public class WidgetUsingGss extends Composite {
+ interface WidgetUsingGssUiBinder extends UiBinder<Widget, WidgetUsingGss> {
+ }
+
+ private static WidgetUsingGssUiBinder uiBinder = GWT.create(WidgetUsingGssUiBinder.class);
+
+ interface GssStyle extends CssResource {
+ String main();
+ }
+
+ @UiField
+ GssStyle style;
+
+ public WidgetUsingGss() {
+ initWidget(uiBinder.createAndBindUi(this));
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml
new file mode 100644
index 0000000..bfe056a
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml
@@ -0,0 +1,18 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+ <ui:style gss="true" type="com.google.gwt.uibinder.test.client.gss.WidgetUsingGss.GssStyle">
+ @def BLACK black;
+
+ @defmixin size(WIDTH, HEIGHT) {
+ width: WIDTH;
+ height: HEIGHT;
+ }
+
+ .main {
+ background-color: BLACK;
+ color: white;
+ @mixin size(200px, 300px);
+ }
+ </ui:style>
+ <g:SimplePanel styleName="{style.main}"/>
+</ui:UiBinder>