Update from trunk@6270
svn merge https://google-web-toolkit.googlecode.com/svn/trunk \
--ignore-ancestry -r6249:6270 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/branches/farewellSwt@6271 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/branch-info.txt b/branch-info.txt
index 21016ee..5d5ecba 100644
--- a/branch-info.txt
+++ b/branch-info.txt
@@ -15,3 +15,5 @@
-r6200:6239 .
svn merge https://google-web-toolkit.googlecode.com/svn/trunk \
-r6239:6249 .
+svn merge https://google-web-toolkit.googlecode.com/svn/trunk \
+ --ignore-ancestry -r6249:6270 .
diff --git a/dev/common.ant.xml b/dev/common.ant.xml
index 178bc62..262d3ba 100755
--- a/dev/common.ant.xml
+++ b/dev/common.ant.xml
@@ -4,7 +4,6 @@
<property.ensure name="gwt.core.root" location="../core" />
<property.ensure name="gwt.core.build" location="${project.build}/../core" />
- <property.ensure name="gwt.tools.soyc" location="${gwt.root}/tools/soyc-vis" />
<target name="compile" description="Compile all java files">
<mkdir dir="${javac.out}" />
@@ -29,9 +28,6 @@
<fileset dir="${javac.out}" />
<fileset dir="${gwt.core.build}/bin" />
<fileset file="${gwt.core.build}/alldeps.jar" />
- <fileset dir="${gwt.tools.soyc}/images"/>
- <fileset file="${gwt.tools.soyc}/classLevel.css"/>
- <fileset file="${gwt.tools.soyc}/roundedCorners.css"/>
</sourcefiles>
<targetfiles>
<fileset file="${project.lib}"/>
@@ -48,10 +44,6 @@
<fileset dir="${gwt.core.build}/bin" />
<zipfileset src="${gwt.core.build}/alldeps.jar" />
- <zipfileset dir="${gwt.tools.soyc}/images" prefix="com/google/gwt/soyc/resources/images"/>
- <zipfileset file="${gwt.tools.soyc}/classLevel.css" prefix="com/google/gwt/soyc/resources/"/>
- <zipfileset file="${gwt.tools.soyc}/roundedCorners.css" prefix="com/google/gwt/soyc/resources/"/>
-
<manifest>
<attribute name="Main-Class" value="com.google.gwt.dev.GWTMain" />
</manifest>
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java b/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java
index 615f333..982499a 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/CompilationAnalysis.java
@@ -16,6 +16,7 @@
package com.google.gwt.core.ext.linker;
import com.google.gwt.core.ext.Linker;
+import com.google.gwt.core.ext.linker.impl.StandardCompilationAnalysis.SoycArtifact;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -41,6 +42,12 @@
public abstract EmittedArtifact getDetailedStoriesFile();
/**
+ * Files containing the HTML dashboard.
+ */
+
+ public abstract List<SoycArtifact> getReportFiles();
+
+ /**
* @return a file of size maps
*/
public abstract EmittedArtifact getSizeMapsFile();
@@ -69,9 +76,12 @@
allFiles());
LinkedList<EmittedArtifact> otherFiles = new LinkedList<EmittedArtifact>(
o.allFiles());
- assert (myFiles.size() == otherFiles.size());
while (!myFiles.isEmpty()) {
+ if (otherFiles.isEmpty()) {
+ return 1;
+ }
+
EmittedArtifact myFile = myFiles.removeFirst();
EmittedArtifact otherFile = otherFiles.removeFirst();
if (myFile == null && otherFile == null) {
@@ -93,6 +103,10 @@
}
}
+ if (!otherFiles.isEmpty()) {
+ return -1;
+ }
+
return 0;
}
@@ -107,6 +121,7 @@
files.add(getDepFile());
files.add(getSizeMapsFile());
files.add(getDetailedStoriesFile());
+ files.addAll(getReportFiles());
return files;
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java
index b9a8969..327c5ba 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationAnalysis.java
@@ -19,6 +19,8 @@
import com.google.gwt.core.ext.linker.SyntheticArtifact;
import com.google.gwt.core.linker.SoycReportLinker;
+import java.util.List;
+
/**
* An implementation of CompilationAnalysis. This class transforms SourceInfos
* and related data into an API suitable for public consumption via the Linker
@@ -48,9 +50,9 @@
private SoycArtifact detailedStoriesFile;
/**
- * File containing split points.
+ * Files containing the HTML dashboard.
*/
- private SoycArtifact splitPointsFile;
+ private List<SoycArtifact> reportFiles;
/**
* File containing size maps.
@@ -58,16 +60,22 @@
private SoycArtifact sizeMapsFile;
/**
+ * File containing split points.
+ */
+ private SoycArtifact splitPointsFile;
+
+ /**
* Constructed by PermutationCompiler.
*/
public StandardCompilationAnalysis(SoycArtifact dependencies,
SoycArtifact sizeMaps, SoycArtifact splitPoints,
- SoycArtifact detailedStories) {
+ SoycArtifact detailedStories, List<SoycArtifact> reportFiles) {
super(StandardLinkerContext.class);
this.depFile = dependencies;
this.sizeMapsFile = sizeMaps;
this.splitPointsFile = splitPoints;
this.detailedStoriesFile = detailedStories;
+ this.reportFiles = reportFiles;
}
@Override
@@ -81,6 +89,11 @@
}
@Override
+ public List<SoycArtifact> getReportFiles() {
+ return reportFiles;
+ }
+
+ @Override
public SoycArtifact getSizeMapsFile() {
return sizeMapsFile;
}
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
index e58edce..a8f648e 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
@@ -108,7 +108,7 @@
protected void recordDependenciesImpl(TreeLogger logger, JProgram jprogram) {
logger = logger.branch(TreeLogger.INFO,
- "Creating Dependencies file for SOYC");
+ "Creating dependencies file for the compile report");
ControlFlowAnalyzer dependencyAnalyzer = new ControlFlowAnalyzer(jprogram);
dependencyAnalyzer.setDependencyRecorder(this);
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
index 597ad33..044de32 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
@@ -40,7 +40,7 @@
TreeLogger logger) {
logger = logger.branch(TreeLogger.TRACE,
- "Creating Split Point Map file for SOYC");
+ "Creating split point map file for the compile report");
try {
OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
index f1708d2..9ad7601 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
@@ -108,7 +108,7 @@
protected void recordStoriesImpl(TreeLogger logger, OutputStream out,
List<Map<Range, SourceInfo>> sourceInfoMaps, String[] js) {
- logger = logger.branch(TreeLogger.INFO, "Creating Stories file for SOYC");
+ logger = logger.branch(TreeLogger.INFO, "Creating Stories file for the compile report");
this.js = js;
diff --git a/dev/core/src/com/google/gwt/core/linker/SoycReportLinker.java b/dev/core/src/com/google/gwt/core/linker/SoycReportLinker.java
index bb32174..2f63ff1 100644
--- a/dev/core/src/com/google/gwt/core/linker/SoycReportLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SoycReportLinker.java
@@ -20,9 +20,17 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.LinkerOrder;
+import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.impl.StandardCompilationAnalysis;
+import com.google.gwt.soyc.SoycDashboard;
+import com.google.gwt.soyc.io.ArtifactsOutputDirectory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.TreeMap;
/**
* Converts SOYC report files into emitted private artifacts.
@@ -32,13 +40,15 @@
@Override
public String getDescription() {
- return "Emit SOYC artifacts";
+ return "Emit compile report artifacts";
}
@Override
public ArtifactSet link(TreeLogger logger, LinkerContext context,
ArtifactSet artifacts) throws UnableToCompleteException {
ArtifactSet results = new ArtifactSet(artifacts);
+ boolean foundReports = false;
+
for (StandardCompilationAnalysis soycFiles : artifacts.find(StandardCompilationAnalysis.class)) {
if (soycFiles.getDepFile() != null) {
results.add(soycFiles.getDepFile());
@@ -50,8 +60,42 @@
results.add(soycFiles.getDetailedStoriesFile());
}
results.add(soycFiles.getSplitPointsFile());
+ if (!soycFiles.getReportFiles().isEmpty()) {
+ results.addAll(soycFiles.getReportFiles());
+ foundReports = true;
+ }
+ }
+
+ if (foundReports) {
+ // run the final step of the dashboard to generate top-level files
+ ArtifactsOutputDirectory out = new ArtifactsOutputDirectory();
+ try {
+ new SoycDashboard(out).generateCrossPermutationFiles(extractPermutationDescriptions(artifacts));
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR,
+ "Error while generating a Story of Your Compile", e);
+ e.printStackTrace();
+ }
+ results.addAll(out.getArtifacts());
}
return results;
}
+ private Map<String, String> extractPermutationDescriptions(
+ ArtifactSet artifacts) {
+ Map<String, String> permDescriptions = new TreeMap<String, String>();
+
+ for (CompilationResult res : artifacts.find(CompilationResult.class)) {
+ String permId = Integer.toString(res.getPermutationId());
+ /*
+ * TODO(kprobst,spoon) support permutations that collapsed to the same
+ * compilation result
+ */
+ Map<SelectionProperty, String> propertyMap = res.getPropertyMap().iterator().next();
+ String permDesc = SymbolMapsLinker.propertyMapToString(propertyMap);
+ permDescriptions.put(permId, permDesc);
+ }
+
+ return permDescriptions;
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
index 3d3ed90..a3dcad3 100644
--- a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
@@ -29,6 +29,7 @@
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Map;
import java.util.SortedMap;
@@ -47,6 +48,33 @@
*/
public static final String STRONG_NAME_SUFFIX = ".symbolMap";
+ public static String propertyMapToString(
+ Map<SelectionProperty, String> propertyMap) {
+ StringWriter writer = new StringWriter();
+ PrintWriter pw = new PrintWriter(writer);
+ printPropertyMap(pw, propertyMap);
+ pw.flush();
+ return writer.toString();
+ }
+
+ private static void printPropertyMap(PrintWriter pw,
+ Map<SelectionProperty, String> map) {
+ boolean needsComma = false;
+ for (Map.Entry<SelectionProperty, String> entry : map.entrySet()) {
+ if (needsComma) {
+ pw.print(" , ");
+ } else {
+ needsComma = true;
+ }
+
+ pw.print("'");
+ pw.print(entry.getKey().getName());
+ pw.print("' : '");
+ pw.print(entry.getValue());
+ pw.print("'");
+ }
+ }
+
@Override
public String getDescription() {
return "Export CompilationResult symbol maps";
@@ -89,26 +117,11 @@
*/
protected void doWriteSymbolMap(TreeLogger logger, CompilationResult result,
PrintWriter pw) throws UnableToCompleteException {
-
pw.println("# { " + result.getPermutationId() + " }");
-
+
for (SortedMap<SelectionProperty, String> map : result.getPropertyMap()) {
pw.print("# { ");
-
- boolean needsComma = false;
- for (Map.Entry<SelectionProperty, String> entry : map.entrySet()) {
- if (needsComma) {
- pw.print(" , ");
- } else {
- needsComma = true;
- }
-
- pw.print("'");
- pw.print(entry.getKey().getName());
- pw.print("' : '");
- pw.print(entry.getValue());
- pw.print("'");
- }
+ printPropertyMap(pw, map);
pw.println(" }");
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index c37c6c3..3f83f66 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -20,6 +20,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.StatementRanges;
import com.google.gwt.core.ext.linker.SymbolData;
import com.google.gwt.core.ext.linker.impl.StandardCompilationAnalysis;
@@ -57,7 +58,6 @@
import com.google.gwt.dev.jjs.impl.CastNormalizer;
import com.google.gwt.dev.jjs.impl.CatchBlockNormalizer;
import com.google.gwt.dev.jjs.impl.CodeSplitter;
-import com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.dev.jjs.impl.ControlFlowAnalyzer;
import com.google.gwt.dev.jjs.impl.DeadCodeElimination;
import com.google.gwt.dev.jjs.impl.EqualityNormalizer;
@@ -85,6 +85,7 @@
import com.google.gwt.dev.jjs.impl.SourceGenerationVisitor;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.jjs.impl.TypeTightener;
+import com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
import com.google.gwt.dev.js.JsBreakUpLargeVarStatements;
import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
@@ -110,12 +111,16 @@
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.TextOutput;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.dev.util.collect.Maps;
+import com.google.gwt.soyc.SoycDashboard;
+import com.google.gwt.soyc.io.ArtifactsOutputDirectory;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.xml.sax.SAXException;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
@@ -130,13 +135,15 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.zip.GZIPInputStream;
+
+import javax.xml.parsers.ParserConfigurationException;
/**
* Compiles the Java <code>JProgram</code> representation into its corresponding
* JavaScript source.
*/
public class JavaToJavaScriptCompiler {
-
private static class PermutationResultImpl implements PermutationResult {
private final ArtifactSet artifacts = new ArtifactSet();
private final byte[][] js;
@@ -318,7 +325,7 @@
// Work around an IE7 bug,
// http://code.google.com/p/google-web-toolkit/issues/detail?id=1440
// note, JsIEBlockTextTransformer now handles restructuring top level
- // blocks, this class now handles non-top level blocks only.
+ // blocks, this class now handles non-top level blocks only.
SelectionProperty userAgentProperty = null;
for (PropertyOracle oracle : propertyOracles) {
userAgentProperty = oracle.getSelectionProperty(logger, "user.agent");
@@ -327,9 +334,8 @@
}
}
// if user agent is known or ie6, split overly large blocks
- boolean splitBlocks = userAgentProperty == null || (
- userAgentProperty != null &&
- "ie6".equals(userAgentProperty.getCurrentValue()));
+ boolean splitBlocks = userAgentProperty == null
+ || (userAgentProperty != null && "ie6".equals(userAgentProperty.getCurrentValue()));
if (splitBlocks) {
JsIEBlockSizeVisitor.exec(jsProgram);
@@ -853,7 +859,7 @@
v = new JsSourceGenerationVisitorWithSizeBreakdown(out, jjsMap);
}
v.accept(jsProgram.getFragmentBlock(i));
-
+
/**
* Reorder function decls to improve compression ratios. Also restructures
* the top level blocks into sub-blocks if they exceed 32767 statements.
@@ -929,10 +935,10 @@
SizeBreakdown[] sizeBreakdowns,
List<Map<Range, SourceInfo>> sourceInfoMaps, SoycArtifact dependencies,
JavaToJavaScriptMap jjsmap, Map<JsName, String> obfuscateMap)
- throws IOException {
+ throws IOException, UnableToCompleteException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- PerfLogger.start("Recording SOYC output");
+ PerfLogger.start("Recording compile report output");
PerfLogger.start("Record split points");
SplitPointRecorder.recordSplitPoints(jprogram, baos, logger);
@@ -964,8 +970,34 @@
PerfLogger.end();
+ List<SoycArtifact> reportArtifacts = Lists.create();
+ if (sizeBreakdowns != null) {
+ PerfLogger.start("Generating compile report");
+ ArtifactsOutputDirectory outDir = new ArtifactsOutputDirectory();
+ SoycDashboard dashboard = new SoycDashboard(outDir);
+ dashboard.startNewPermutation(Integer.toString(permutationId));
+ try {
+ dashboard.readSplitPoints(openWithGunzip(splitPoints));
+ if (sizeMaps != null) {
+ dashboard.readSizeMaps(openWithGunzip(sizeMaps));
+ }
+ if (dependencies != null) {
+ dashboard.readDependencies(openWithGunzip(dependencies));
+ }
+ } catch (ParserConfigurationException e) {
+ throw new InternalCompilerException(
+ "Error reading compile report information that was just generated", e);
+ } catch (SAXException e) {
+ throw new InternalCompilerException(
+ "Error reading compile report information that was just generated", e);
+ }
+ dashboard.generateForOnePermutation();
+ reportArtifacts = outDir.getArtifacts();
+ PerfLogger.end();
+ }
+
return new StandardCompilationAnalysis(dependencies, sizeMaps, splitPoints,
- detailedStories);
+ detailedStories, reportArtifacts);
}
/**
@@ -1032,6 +1064,14 @@
}
/**
+ * Open an emitted artifact and gunzip its contents.
+ */
+ private static GZIPInputStream openWithGunzip(EmittedArtifact artifact)
+ throws IOException, UnableToCompleteException {
+ return new GZIPInputStream(artifact.getContents(TreeLogger.NULL));
+ }
+
+ /**
* Dependency information is normally recorded during code splitting, and it
* results in multiple dependency graphs. If the code splitter doesn't run,
* then this method can be used instead to record a single dependency graph
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoycDetailed.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoycDetailed.java
index d8b78c9..c278399 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoycDetailed.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerSoycDetailed.java
@@ -29,7 +29,7 @@
@Override
public String getPurpose() {
- return "Emit extra, detailed SOYC information at the expense of compile time";
+ return "Emit extra, detailed compile-report information at the expense of compile time";
}
@Override
diff --git a/dev/core/src/com/google/gwt/soyc/GlobalInformation.java b/dev/core/src/com/google/gwt/soyc/GlobalInformation.java
index aaf9edf..34262db 100644
--- a/dev/core/src/com/google/gwt/soyc/GlobalInformation.java
+++ b/dev/core/src/com/google/gwt/soyc/GlobalInformation.java
@@ -25,10 +25,11 @@
import java.util.TreeSet;
/**
- * Information global to the entire SOYC report generator.
+ * SOYC information about a compiled module.
*/
public class GlobalInformation {
private static final SizeBreakdown[] EMPTY_SIZE_BREAKDOWN = new SizeBreakdown[0];
+ public Map<String, Map<String, String>> dependencies = null;
private HashMap<String, String> classToPackage = new HashMap<String, String>();
private HashMap<String, HashSet<String>> classToWhatItDependsOn = new HashMap<String, HashSet<String>>();
private Map<Integer, SizeBreakdown> exclusiveCodeBreakdowns = new HashMap<Integer, SizeBreakdown>();
@@ -38,11 +39,16 @@
"Leftovers code, code not in any other category", "leftovers");
private int numSplitPoints = 0;
private Map<String, TreeSet<String>> packageToClasses = new TreeMap<String, TreeSet<String>>();
+ private final String permutationId;
private ArrayList<Integer> splitPointInitialLoadSequence = new ArrayList<Integer>();
private HashMap<Integer, String> splitPointToLocation = new HashMap<Integer, String>();
private SizeBreakdown totalCodeBreakdown = new SizeBreakdown("Total program",
"total");
+ public GlobalInformation(String permutationId) {
+ this.permutationId = permutationId;
+ }
+
public SizeBreakdown[] allSizeBreakdowns() {
List<SizeBreakdown> breakdowns = new ArrayList<SizeBreakdown>();
breakdowns.add(totalCodeBreakdown);
@@ -128,6 +134,10 @@
return packageToClasses;
}
+ public String getPermutationId() {
+ return permutationId;
+ }
+
/**
* Gets the initial load sequence.
*
diff --git a/dev/core/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java b/dev/core/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
index 9c63ffb..79d9258 100644
--- a/dev/core/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
+++ b/dev/core/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
@@ -17,13 +17,9 @@
package com.google.gwt.soyc;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.soyc.io.OutputDirectory;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
@@ -33,9 +29,6 @@
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.JarInputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,24 +37,14 @@
*/
public class MakeTopLevelHtmlForPerm {
/**
- * A dependency linker for exclusive fragments. It links to nothing.
- */
- public class DependencyLinkerForExclusiveFragment implements DependencyLinker {
- public String dependencyLinkForClass(String className, String permutationId) {
- return null;
- }
- }
-
- /**
* A dependency linker for the initial code download. It links to the
* dependencies for the initial download.
*/
public class DependencyLinkerForInitialCode implements DependencyLinker {
- public String dependencyLinkForClass(String className, String permutationId) {
+ public String dependencyLinkForClass(String className) {
String packageName = globalInformation.getClassToPackage().get(className);
assert packageName != null;
- return dependenciesFileName("initial", packageName, permutationId) + "#"
- + className;
+ return dependenciesFileName("initial", packageName) + "#" + className;
}
}
@@ -70,8 +53,8 @@
* status pages.
*/
public class DependencyLinkerForLeftoversFragment implements DependencyLinker {
- public String dependencyLinkForClass(String className, String permutationId) {
- return leftoversStatusFileName(className, permutationId);
+ public String dependencyLinkForClass(String className) {
+ return leftoversStatusFileName(className);
}
}
@@ -81,13 +64,22 @@
*
*/
public class DependencyLinkerForTotalBreakdown implements DependencyLinker {
- public String dependencyLinkForClass(String className, String permutationId) {
- return splitStatusFileName(className, permutationId);
+ public String dependencyLinkForClass(String className) {
+ return splitStatusFileName(className);
+ }
+ }
+
+ /**
+ * A dependency linker that never links to anything.
+ */
+ public static class NullDependencyLinker implements DependencyLinker {
+ public String dependencyLinkForClass(String className) {
+ return null;
}
}
interface DependencyLinker {
- String dependencyLinkForClass(String className, String permutationId);
+ String dependencyLinkForClass(String className);
}
/**
@@ -110,10 +102,6 @@
*/
private static final Pattern PATTERN_SP_INT = Pattern.compile("sp([0-9]+)");
- private static String RESOURCES_PATH = MakeTopLevelHtmlForPerm.class.getPackage().getName().replace(
- '.', '/')
- + "/resources/";
-
public static String escapeXml(String unescaped) {
String escaped = unescaped.replaceAll("\\&", "&");
escaped = escaped.replaceAll("\\<", "<");
@@ -123,6 +111,46 @@
return escaped;
}
+ public static void makeTopLevelHtmlForAllPerms(
+ Map<String, String> allPermsInfo, OutputDirectory outDir)
+ throws IOException {
+ PrintWriter outFile = new PrintWriter(outDir.getOutputStream("index.html"));
+
+ outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">");
+ outFile.println("<html>");
+ outFile.println("<head>");
+ outFile.println(" <title>Story of Your Compile - Top Level Dashboard for all Permutations</title>");
+ outFile.println("<style type=\"text/css\">");
+ outFile.println("body {background-color: #728FCE}");
+ outFile.println("h2 {background-color: transparent}");
+ outFile.println("</style>");
+ outFile.println("</head>");
+
+ outFile.println("<body>");
+ outFile.println("<center>");
+ outFile.println("<h1>Story of Your Compile</h1>");
+ outFile.println("<hr>");
+ outFile.println("<h3>Story of Your Compile - Overview of Permutations</h3>");
+ outFile.println("<hr>");
+
+ outFile.println("<div style='overflow:auto; background-color:white'>");
+ outFile.println("<center>");
+ for (String permutationId : allPermsInfo.keySet()) {
+ String permutationInfo = allPermsInfo.get(permutationId);
+ outFile.print("<p><a href=\"SoycDashboard" + "-" + permutationId
+ + "-index.html\">Permutation " + permutationId);
+ if (permutationInfo.length() > 0) {
+ outFile.println(" (" + permutationInfo + ")" + "</a>");
+ } else {
+ outFile.println("</a>");
+ }
+ }
+ outFile.println("</center>");
+ outFile.println("</div>");
+ addStandardHtmlEnding(outFile);
+ outFile.close();
+ }
+
private static void addCenteredHeader(final PrintWriter outFile, String header) {
outFile.println("<hr>");
outFile.println("<b>" + header + "</b>");
@@ -137,6 +165,37 @@
addCenteredHeader(outFile, headerLineForBreakdown(breakdown));
}
+ private static void addStandardHtmlEnding(final PrintWriter out) {
+ out.println("</div>");
+ out.println("</body>");
+ out.println("</html>");
+ }
+
+ private static void addStandardHtmlProlog(final PrintWriter out,
+ String title, String header) {
+ out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ out.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ out.println("<html>");
+ out.println("<head>");
+ out.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
+ out.println("<title>" + title + "</title>");
+ out.println("</head>");
+
+ out.println("<style type=\"text/css\">");
+ out.println("body {background-color: #728FCE}");
+ out.println("h2 {background-color: transparent}");
+ out.println("p {background-color: fuchsia}");
+ out.println("</style>");
+
+ out.println("<body>");
+ out.println("<center>");
+ out.println("<h2>" + title + "</h2>");
+ if (header != null) {
+ addCenteredHeader(out, header);
+ }
+ out.println("</center>");
+ }
+
private static String classesInPackageFileName(SizeBreakdown breakdown,
String packageName, String permutationId) {
return breakdown.getId() + "_" + packageName + "-" + permutationId
@@ -167,155 +226,22 @@
/**
* Global information for this permutation.
*/
- private GlobalInformation globalInformation = new GlobalInformation();
+ private final GlobalInformation globalInformation;
- /**
- * Settings for this permutation.
- */
- private Settings settings = new Settings();
+ private final OutputDirectory outDir;
- /**
- * Default constructor. Will be used for all permutations.
- */
- MakeTopLevelHtmlForPerm() {
- this.globalInformation = new GlobalInformation();
- this.settings = new Settings();
- }
-
- /**
- * Constructor for a specific permutation.
- *
- * @param globalInformation All the information about this permutation
- */
- MakeTopLevelHtmlForPerm(final GlobalInformation globalInformation) {
+ MakeTopLevelHtmlForPerm(GlobalInformation globalInformation,
+ OutputDirectory outDir) {
this.globalInformation = globalInformation;
+ this.outDir = outDir;
}
- public void copyFileOrDirectory(File srcPath, File dstPath, String classPath,
- String inputFileName, boolean isDirectory) throws IOException {
- if (srcPath.isDirectory()) {
- if (!dstPath.exists()) {
- dstPath.mkdir();
- }
- String files[] = srcPath.list();
- for (int i = 0; i < files.length; i++) {
- copyFileOrDirectory(new File(srcPath, files[i]), new File(dstPath,
- files[i]), classPath, inputFileName, isDirectory);
- }
- } else {
- if (!srcPath.exists()) {
- copyFileOrDirectoryFromJar(classPath, inputFileName, dstPath,
- isDirectory);
- } else {
- InputStream in = new FileInputStream(srcPath);
- OutputStream out = new FileOutputStream(dstPath);
- // Transfer bytes from in to out
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- in.close();
- out.close();
- }
- }
- }
-
- public void copyFileOrDirectoryFromJar(String jarFileName,
- String inputFileName, File dstPath, boolean isDirectory)
- throws IOException {
-
- JarFile jarFile = new JarFile(jarFileName);
- if (isDirectory) {
- dstPath.mkdir();
-
- JarInputStream jarFileIS = new JarInputStream(new FileInputStream(
- jarFileName));
- JarEntry jarEntry = jarFileIS.getNextJarEntry();
- while (jarEntry != null) {
- if (!inputFileName.endsWith("/")) {
- inputFileName += "/";
- }
- if ((jarEntry.getName().compareTo(inputFileName) != 0)
- && (jarEntry.getName().startsWith(inputFileName))) {
- File newDstPath = getOutFile(jarEntry.getName());
- copyFileOrDirectoryFromJar(jarFileName, jarEntry.getName(),
- newDstPath, false);
- }
- jarEntry = jarFileIS.getNextJarEntry();
- }
- jarFileIS.close();
- } else {
- InputStream in = jarFile.getInputStream(jarFile.getEntry(inputFileName));
- OutputStream out = new FileOutputStream(dstPath);
-
- int c;
- while ((c = in.read()) != -1) {
- out.write(c);
- }
- in.close();
- out.close();
- jarFile.close();
- }
- }
-
- public GlobalInformation getGlobalInformation() {
- return globalInformation;
- }
-
- public void makeBreakdownShell(SizeBreakdown breakdown, String permutationId)
- throws IOException {
- // this will contain the place holder iframes where the actual information
- // is going to go.
-
+ public void makeBreakdownShell(SizeBreakdown breakdown) throws IOException {
Map<String, CodeCollection> nameToCodeColl = breakdown.nameToCodeColl;
Map<String, LiteralsCollection> nameToLitColl = breakdown.nameToLitColl;
- // copy from the bin directory to the current directory
- String classPath = settings.resources.get();
- if (classPath == null) {
- classPath = System.getProperty("java.class.path");
- }
- if (!classPath.endsWith("/")) {
- classPath += "/";
- }
- String inputFileName = "roundedCorners.css";
- File inputFile = new File(classPath + RESOURCES_PATH + inputFileName);
- if (!inputFile.exists()) {
- inputFile = new File(classPath + inputFileName);
- }
- File outputFile = getOutFile("roundedCorners.css");
- copyFileOrDirectory(inputFile, outputFile, classPath, RESOURCES_PATH
- + inputFileName, false);
-
- inputFileName = "classLevel.css";
- File inputFile2 = new File(classPath + RESOURCES_PATH + inputFileName);
- if (!inputFile2.exists()) {
- inputFile2 = new File(classPath + inputFileName);
- }
- File outputFile2 = getOutFile("classLevel.css");
- copyFileOrDirectory(inputFile2, outputFile2, classPath, RESOURCES_PATH
- + inputFileName, false);
-
- inputFileName = "common.css";
- File inputFile3 = new File(classPath + RESOURCES_PATH + inputFileName);
- if (!inputFile3.exists()) {
- inputFile3 = new File(classPath + inputFileName);
- }
- File outputFile3 = getOutFile("common.css");
- copyFileOrDirectory(inputFile3, outputFile3, classPath, RESOURCES_PATH
- + inputFileName, false);
-
- inputFileName = "images";
- File inputDir = new File(classPath + RESOURCES_PATH + "images");
- if (!inputDir.exists()) {
- inputDir = new File(classPath + "images");
- }
- File outputDir = getOutFile("images");
- copyFileOrDirectory(inputDir, outputDir, classPath, inputFileName, true);
-
- final PrintWriter outFile = new PrintWriter(getOutFile(shellFileName(
- breakdown, permutationId)));
+ PrintWriter outFile = new PrintWriter(getOutFile(shellFileName(breakdown,
+ getPermutationId())));
outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">");
outFile.println("<html>");
@@ -389,7 +315,7 @@
outFile.println("<div class='abs header'>Package breakdown</div>");
outFile.println("<div class='abs innerContent'>");
- String packageBreakdownFileName = makePackageHtml(breakdown, permutationId);
+ String packageBreakdownFileName = makePackageHtml(breakdown);
outFile.println(" <iframe class='frame' src=\"" + packageBreakdownFileName
+ "\" scrolling=auto></iframe>");
outFile.println("</div>");
@@ -400,7 +326,7 @@
outFile.println("<div class='abs innerContent'>");
String codeTypeBreakdownFileName = makeCodeTypeHtml(breakdown,
- nameToCodeColl, nameToLitColl, permutationId);
+ nameToCodeColl, nameToLitColl);
outFile.println("<iframe class='frame' src=\"" + codeTypeBreakdownFileName
+ "\" scrolling=auto></iframe>");
outFile.println("</div>");
@@ -411,15 +337,15 @@
outFile.close();
}
- public void makeCodeTypeClassesHtmls(SizeBreakdown breakdown,
- String permutationId) throws IOException {
+ public void makeCodeTypeClassesHtmls(SizeBreakdown breakdown)
+ throws IOException {
HashMap<String, CodeCollection> nameToCodeColl = breakdown.nameToCodeColl;
for (String codeType : nameToCodeColl.keySet()) {
// construct file name
String outFileName = breakdown.getId() + "_" + codeType + "-"
- + permutationId + "Classes.html";
+ + getPermutationId() + "Classes.html";
float maxSize = 0f;
TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(
@@ -540,28 +466,26 @@
}
}
- public void makeDependenciesHtml(
- Map<String, Map<String, String>> allDependencies, String permutationId)
- throws IOException {
- for (String depGraphName : allDependencies.keySet()) {
- makeDependenciesHtml(depGraphName, allDependencies.get(depGraphName),
- permutationId);
+ public void makeDependenciesHtml() throws IOException {
+ for (String depGraphName : globalInformation.dependencies.keySet()) {
+ makeDependenciesHtml(depGraphName,
+ globalInformation.dependencies.get(depGraphName));
}
}
- public void makeLeftoverStatusPages(String permutationId) throws IOException {
+ public void makeLeftoverStatusPages() throws IOException {
for (String className : globalInformation.getClassToPackage().keySet()) {
- makeLeftoversStatusPage(className, permutationId);
+ makeLeftoversStatusPage(className);
}
}
- public void makeLiteralsClassesTableHtmls(SizeBreakdown breakdown,
- String permutationId) throws IOException {
+ public void makeLiteralsClassesTableHtmls(SizeBreakdown breakdown)
+ throws IOException {
Map<String, LiteralsCollection> nameToLitColl = breakdown.nameToLitColl;
for (String literalType : nameToLitColl.keySet()) {
- String outFileName = literalType + "-" + permutationId + "Lits.html";
+ String outFileName = literalType + "-" + getPermutationId() + "Lits.html";
final PrintWriter outFile = new PrintWriter(getOutFile(breakdown.getId()
+ "_" + outFileName));
@@ -625,9 +549,8 @@
* Make size breakdowns for each package for one code collection.
*/
public void makePackageClassesHtmls(SizeBreakdown breakdown,
- DependencyLinker depLinker, String permutationId) throws IOException {
+ DependencyLinker depLinker) throws IOException {
for (String packageName : globalInformation.getPackageToClasses().keySet()) {
-
TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(
Collections.reverseOrder());
float maxSize = 0f;
@@ -642,7 +565,6 @@
}
if (curSize != 0f) {
-
sumSize += curSize;
sortedClasses.put(curSize, className);
if (curSize > maxSize) {
@@ -653,7 +575,7 @@
PrintWriter outFile = new PrintWriter(
getOutFile(classesInPackageFileName(breakdown, packageName,
- permutationId)));
+ getPermutationId())));
outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
@@ -726,9 +648,8 @@
outFile.println("<th class='barlabel'></th>");
outFile.println("<th style='width:100%' class='barlabel'></th>");
outFile.println("</thead>");
-//
- for (Float size : sortedClasses.keySet()) {
+ for (Float size : sortedClasses.keySet()) {
String className = sortedClasses.get(size);
float ratio = (size / maxSize) * 85;
if (ratio < 5) {
@@ -736,12 +657,11 @@
}
float perc = (size / sumSize) * 100;
- String dependencyLink = depLinker.dependencyLinkForClass(className,
- permutationId);
+ String dependencyLink = depLinker.dependencyLinkForClass(className);
outFile.println("<tr>");
outFile.println("<td class=\"barlabel\">" + size + "</td>");
outFile.println("<td class=\"barlabel\">" + perc + "%</td>");
- if ((settings.displayDependencies) && (dependencyLink != null)) {
+ if (dependencyLink != null) {
outFile.println("<td class=\"barlabel\"><a href=\"" + dependencyLink
+ "\" target=\"_top\">" + className + "</a></td>");
} else {
@@ -761,54 +681,15 @@
}
}
- public void makeSplitStatusPages(String permutationId) throws IOException {
+ public void makeSplitStatusPages() throws IOException {
for (String className : globalInformation.getClassToPackage().keySet()) {
- makeSplitStatusPage(className, permutationId);
+ makeSplitStatusPage(className);
}
}
- public void makeTopLevelHtmlForAllPerms() throws FileNotFoundException {
-
- PrintWriter outFile = new PrintWriter(getOutFile("index.html"));
-
- outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">");
- outFile.println("<html>");
- outFile.println("<head>");
- outFile.println(" <title>Story of Your Compile - Top Level Dashboard for all Permutations</title>");
- outFile.println("<style type=\"text/css\">");
- outFile.println("body {background-color: #728FCE}");
- outFile.println("h2 {background-color: transparent}");
- outFile.println("</style>");
- outFile.println("</head>");
-
- outFile.println("<body>");
- outFile.println("<center>");
- outFile.println("<h1>Story of Your Compile</h1>");
- outFile.println("<hr>");
- outFile.println("<h3>Story of Your Compile - Overview of Permutations</h3>");
- outFile.println("<hr>");
-
- outFile.println("<div style='overflow:auto; background-color:white'>");
- outFile.println("<center>");
- for (String permutationId : settings.allPermsInfo.keySet()) {
- String permutationInfo = settings.allPermsInfo.get(permutationId);
- outFile.print("<p><a href=\"SoycDashboard" + "-" + permutationId
- + "-index.html\">Permutation " + permutationId);
- if (permutationInfo.length() > 0) {
- outFile.println(" (" + permutationInfo + ")" + "</a>");
- } else {
- outFile.println("</a>");
- }
- }
- outFile.println("</center>");
- outFile.println("</div>");
- addStandardHtmlEnding(outFile);
- outFile.close();
- }
-
- public void makeTopLevelShell(String permutationId) throws IOException {
+ public void makeTopLevelShell() throws IOException {
PrintWriter outFile = new PrintWriter(getOutFile("SoycDashboard" + "-"
- + permutationId + "-index.html"));
+ + getPermutationId() + "-index.html"));
outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
@@ -868,8 +749,10 @@
outFile.println("<body>");
outFile.println("<div class='abs mainHeader'>");
outFile.println("<h2>Story of Your Compile Dashboard</h2>");
- String permutationInfo = settings.allPermsInfo.get(permutationId);
- outFile.print("<h3>Permutation " + permutationId);
+ // String permutationInfo = settings.allPermsInfo.get(getPermutationId());
+ String permutationInfo = ""; // TODO(spoon) pass in permutation information
+ // here
+ outFile.print("<h3>Permutation " + getPermutationId());
if (permutationInfo.length() > 0) {
outFile.println(" (" + permutationInfo + ")");
}
@@ -928,7 +811,7 @@
breakdown = globalInformation.splitPointCodeBreakdown(i);
}
- String drillDownFileName = shellFileName(breakdown, permutationId);
+ String drillDownFileName = shellFileName(breakdown, getPermutationId());
String splitPointDescription = breakdown.getDescription();
int size = breakdown.sizeAllCode;
@@ -962,14 +845,6 @@
outFile.close();
}
- public void setGlobalInformation(GlobalInformation globalInformation) {
- this.globalInformation = globalInformation;
- }
-
- public void setSettings(Settings settings) {
- this.settings = settings;
- }
-
private void addDependenciesHtmlProlog(final PrintWriter out, String title,
String header) {
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
@@ -1023,65 +898,39 @@
}
private void addLefttoversStatus(String className, String packageName,
- PrintWriter out, String permutationId) {
- if (settings.displayDependencies) {
+ PrintWriter out) {
+ if (globalInformation.dependencies != null) {
out.println("<tr><td> <a href=\""
- + dependenciesFileName("total", packageName, permutationId) + "#"
- + className + "\">See why it's live</a></td></tr>");
+ + dependenciesFileName("total", packageName) + "#" + className
+ + "\">See why it's live</a></td></tr>");
for (int sp = 1; sp <= globalInformation.getNumSplitPoints(); sp++) {
out.println("<tr><td> <a href=\""
- + dependenciesFileName("sp" + sp, packageName, permutationId) + "#"
- + className + "\">See why it's not exclusive to s.p. #" + sp + " ("
+ + dependenciesFileName("sp" + sp, packageName) + "#" + className
+ + "\">See why it's not exclusive to s.p. #" + sp + " ("
+ globalInformation.getSplitPointToLocation().get(sp)
+ ")</a></td></tr>");
}
}
}
- private void addStandardHtmlEnding(final PrintWriter out) {
- out.println("</div>");
- out.println("</body>");
- out.println("</html>");
- }
-
- private void addStandardHtmlProlog(final PrintWriter out, String title,
- String header) {
- out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
- out.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
- out.println("<html>");
- out.println("<head>");
- out.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
- out.println("<title>" + title + "</title>");
- out.println("</head>");
-
- out.println("<style type=\"text/css\">");
- out.println("body {background-color: #728FCE}");
- out.println("h2 {background-color: transparent}");
- out.println("p {background-color: fuchsia}");
- out.println("</style>");
-
- out.println("<body>");
- out.println("<center>");
- out.println("<h2>" + title + "</h2>");
- if (header != null) {
- addCenteredHeader(out, header);
- }
- out.println("</center>");
- }
-
- private String dependenciesFileName(String depGraphName, String packageName,
- String permutationId) {
+ private String dependenciesFileName(String depGraphName, String packageName) {
return "methodDependencies-" + depGraphName + "-" + filename(packageName)
- + "-" + permutationId + ".html";
+ + "-" + getPermutationId() + ".html";
}
/**
* Return a {@link File} object for a file to be emitted into the output
* directory.
*/
- private File getOutFile(String localFileName) {
- File outDir = new File(settings.out.get());
- return new File(outDir, localFileName);
+ private OutputStream getOutFile(String localFileName) throws IOException {
+ return outDir.getOutputStream(localFileName);
+ }
+
+ /**
+ * @return
+ */
+ private String getPermutationId() {
+ return globalInformation.getPermutationId();
}
/**
@@ -1115,16 +964,15 @@
splitPoint);
}
- private String leftoversStatusFileName(String className, String permutationId) {
- return "leftoverStatus-" + filename(className) + "-" + permutationId
+ private String leftoversStatusFileName(String className) {
+ return "leftoverStatus-" + filename(className) + "-" + getPermutationId()
+ ".html";
}
private String makeCodeTypeHtml(SizeBreakdown breakdown,
Map<String, CodeCollection> nameToCodeColl,
- Map<String, LiteralsCollection> nameToLitColl, String permutationId)
- throws IOException {
- String outFileName = breakdown.getId() + "-" + permutationId
+ Map<String, LiteralsCollection> nameToLitColl) throws IOException {
+ String outFileName = breakdown.getId() + "-" + getPermutationId()
+ "_codeTypeBreakdown.html";
float maxSize = 0f;
float sumSize = 0f;
@@ -1167,7 +1015,7 @@
String codeType = sortedCodeTypes.get(size);
String drillDownFileName = breakdown.getId() + "_" + codeType + "-"
- + permutationId + "Classes.html";
+ + getPermutationId() + "Classes.html";
float ratio = (size / maxSize) * 79;
float perc = (size / sumSize) * 100;
@@ -1210,7 +1058,7 @@
for (Float size : sortedLitTypes.keySet()) {
String literal = sortedLitTypes.get(size);
String drillDownFileName = breakdown.getId() + "_" + literal + "-"
- + permutationId + "Lits.html";
+ + getPermutationId() + "Lits.html";
float ratio = (size / maxSize) * 79;
float perc = (size / sumSize) * 100;
@@ -1241,8 +1089,7 @@
}
private void makeDependenciesHtml(String depGraphName,
- Map<String, String> dependencies, String permutationId)
- throws FileNotFoundException {
+ Map<String, String> dependencies) throws IOException {
String depGraphDescription = inferDepGraphDescription(depGraphName);
PrintWriter outFile = null;
String curPackageName = "";
@@ -1268,8 +1115,7 @@
outFile.close();
}
- String outFileName = dependenciesFileName(depGraphName, curPackageName,
- permutationId);
+ String outFileName = dependenciesFileName(depGraphName, curPackageName);
outFile = new PrintWriter(getOutFile(outFileName));
String packageDescription = packageName.length() == 0
@@ -1305,11 +1151,10 @@
outFile.close();
}
- private void makeLeftoversStatusPage(String className, String permutationId)
- throws IOException {
+ private void makeLeftoversStatusPage(String className) throws IOException {
String packageName = globalInformation.getClassToPackage().get(className);
- PrintWriter out = new PrintWriter(getOutFile(leftoversStatusFileName(
- className, permutationId)));
+ PrintWriter out = new PrintWriter(
+ getOutFile(leftoversStatusFileName(className)));
addStandardHtmlProlog(out, "Leftovers page for " + className, null);
@@ -1317,7 +1162,7 @@
out.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
out.println("<tr><td>This class has some leftover code, neither initial nor exclusive to any split point:</td></tr>");
- addLefttoversStatus(className, packageName, out, permutationId);
+ addLefttoversStatus(className, packageName, out);
out.println("</table>");
addStandardHtmlEnding(out);
@@ -1325,9 +1170,8 @@
out.close();
}
- private String makePackageHtml(SizeBreakdown breakdown, String permutationId)
- throws FileNotFoundException {
- String outFileName = breakdown.getId() + "-" + permutationId + "_"
+ private String makePackageHtml(SizeBreakdown breakdown) throws IOException {
+ String outFileName = breakdown.getId() + "-" + getPermutationId() + "_"
+ "packageBreakdown.html";
Map<String, Integer> packageToPartialSize = breakdown.packageToSize;
TreeMap<Integer, String> sortedPackages = new TreeMap<Integer, String>(
@@ -1364,7 +1208,7 @@
for (int size : sortedPackages.keySet()) {
String packageName = sortedPackages.get(size);
String drillDownFileName = classesInPackageFileName(breakdown,
- packageName, permutationId);
+ packageName, getPermutationId());
float ratio = (size / maxSize) * 79;
if (ratio < 5) {
@@ -1393,11 +1237,10 @@
return outFileName;
}
- private void makeSplitStatusPage(String className, String permutationId)
- throws IOException {
+ private void makeSplitStatusPage(String className) throws IOException {
String packageName = globalInformation.getClassToPackage().get(className);
- PrintWriter out = new PrintWriter(getOutFile(splitStatusFileName(className,
- permutationId)));
+ PrintWriter out = new PrintWriter(
+ getOutFile(splitStatusFileName(className)));
addStandardHtmlProlog(out, "Split point status for " + className, null);
@@ -1405,10 +1248,10 @@
out.println("<table border=\"1\" width=\"80%\" style=\"font-size: 11pt;\" bgcolor=\"white\">");
if (globalInformation.getInitialCodeBreakdown().classToSize.containsKey(className)) {
- if (settings.displayDependencies) {
+ if (globalInformation.dependencies != null) {
out.println("<tr><td>Some code is initial (<a href=\""
- + dependenciesFileName("initial", packageName, permutationId) + "#"
- + className + "\">see why</a>)</td></tr>");
+ + dependenciesFileName("initial", packageName) + "#" + className
+ + "\">see why</a>)</td></tr>");
} else {
out.println("<tr><td>Some code is initial</td></tr>");
}
@@ -1419,7 +1262,7 @@
}
if (globalInformation.getLeftoversBreakdown().classToSize.containsKey(className)) {
out.println("<tr><td>Some code is left over:</td></tr>");
- addLefttoversStatus(className, packageName, out, permutationId);
+ addLefttoversStatus(className, packageName, out);
}
out.println("</table>");
@@ -1442,7 +1285,8 @@
return sps;
}
- private String splitStatusFileName(String className, String permutationId) {
- return "splitStatus-" + filename(className) + "-" + permutationId + ".html";
+ private String splitStatusFileName(String className) {
+ return "splitStatus-" + filename(className) + "-" + getPermutationId()
+ + ".html";
}
}
diff --git a/dev/core/src/com/google/gwt/soyc/Settings.java b/dev/core/src/com/google/gwt/soyc/Settings.java
index 7f5b9bb..01bd6e8 100644
--- a/dev/core/src/com/google/gwt/soyc/Settings.java
+++ b/dev/core/src/com/google/gwt/soyc/Settings.java
@@ -16,15 +16,10 @@
package com.google.gwt.soyc;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.TreeMap;
/**
* Command-line settings for SOYC.
@@ -123,10 +118,6 @@
break; // No setting wanted the remaining arguments
}
- if (settings.resources.get() == null) {
- throw new ArgumentListException("The -resources option is required");
- }
-
if ((settings.soycDir.get() == null)
&& (settings.symbolMapsDir.get() == null)) {
@@ -184,17 +175,16 @@
return help.toString();
}
- public Map<String, String> allPermsInfo = new TreeMap<String, String>();
public String depFileName;
- public Boolean displayDependencies = false;
- public Boolean displaySplitPoints = false;
public final Setting<String> out = addSetting(new StringSetting("-out",
"dir", ".", "output directory"));
public final Setting<String> resources = addSetting(new StringSetting(
- "-resources", "jarfile", null,
- " directory or jar file with CSS, etc., resources"));
+ "-resources",
+ "dir",
+ null,
+ "present only for backwards compatibility; directory or jar file with CSS, etc., resources"));
public final Setting<String> soycDir = addSetting(new StringSetting(
"-soycDir", "dir", null, " directory for soyc files"));
@@ -207,47 +197,6 @@
"-symbolMapsDir", "dir", null, " directory or symbol maps files"));
private List<Setting<?>> allSettings;
- public void readPermutationInfo() throws FileNotFoundException {
-
- if (symbolMapsDir.get() == null) {
- // get the permutation id from settings
- String permutationId = storiesFileName;
- permutationId = permutationId.replaceAll(".*/stories", "");
- permutationId = permutationId.replaceAll("\\.xml(\\.gz)?", "");
- allPermsInfo.put(permutationId, "");
- } else {
- File dir = new File(symbolMapsDir.get());
- String files[] = dir.list();
- for (Integer i = 0; i < files.length; i++) {
- String permFileName = symbolMapsDir.get() + "/" + files[i];
- FileReader fir = new FileReader(permFileName);
-
- Scanner sc = new Scanner(fir);
-
- String permutationId = "";
- String permutationInfo = "";
- int lineCount = 0;
- while ((sc.hasNextLine()) && (lineCount < 2)) {
-
- String curLine = sc.nextLine();
- curLine = curLine.trim();
-
- if (curLine.startsWith("# {")) {
- curLine = curLine.replace("# {", "");
- curLine = curLine.replace("}", "");
- curLine = curLine.trim();
- if (lineCount == 0) {
- permutationId = curLine;
- } else {
- permutationInfo = curLine;
- }
- lineCount++;
- }
- }
- allPermsInfo.put(permutationId, permutationInfo);
- }
- }
- }
private <T> Setting<T> addSetting(Setting<T> setting) {
if (allSettings == null) {
diff --git a/dev/core/src/com/google/gwt/soyc/SoycDashboard.java b/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
index 25aeffd..190256f 100644
--- a/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
+++ b/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
@@ -17,6 +17,9 @@
package com.google.gwt.soyc;
import com.google.gwt.soyc.MakeTopLevelHtmlForPerm.DependencyLinker;
+import com.google.gwt.soyc.MakeTopLevelHtmlForPerm.NullDependencyLinker;
+import com.google.gwt.soyc.io.FileSystemOutputDirectory;
+import com.google.gwt.soyc.io.OutputDirectory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -26,6 +29,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -33,6 +37,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
@@ -43,10 +48,9 @@
import javax.xml.parsers.SAXParserFactory;
/**
- * The command-line entry point for creating a SOYC report.
+ * The command-line entry point for creating a compile report.
*/
public class SoycDashboard {
-
private static class FormatException extends RuntimeException {
public FormatException() {
super();
@@ -62,136 +66,47 @@
}
public static void main(final String[] args) {
+ Settings settings;
try {
- System.out.println("Generating the Story of Your Compile...");
- Settings settings = Settings.fromArgumentList(args);
+ settings = Settings.fromArgumentList(args);
+ } catch (Settings.ArgumentListException e) {
+ System.err.println(e.getMessage());
+ System.err.println("Usage: "
+ + "java com.google.gwt.soyc.SoycDashboard -resources dir -soycDir dir -symbolMaps dir [-out dir]");
+ System.err.println("(Legacy usage: "
+ + "java com.google.gwt.soyc.SoycDashboard options stories0.xml[.gz] [dependencies0.xml[.gz]] [splitpoints0.xml[.gz]])");
+ System.err.println("Options:");
+ System.err.println(Settings.settingsHelp());
+ System.exit(1);
+ return; // not reached
+ }
- MakeTopLevelHtmlForPerm makeTopLevelHtml = new MakeTopLevelHtmlForPerm();
- makeTopLevelHtml.setSettings(settings);
+ System.out.println("Generating the Story of Your Compile...");
- // read in all the symbol maps
- settings.readPermutationInfo();
- makeTopLevelHtml.makeTopLevelHtmlForAllPerms();
- for (String permutationId : settings.allPermsInfo.keySet()) {
- GlobalInformation globalInformation = new GlobalInformation();
- MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm = new MakeTopLevelHtmlForPerm(
- globalInformation);
- makeTopLevelHtmlForPerm.setSettings(settings);
+ OutputDirectory outDir = new FileSystemOutputDirectory(new File(
+ settings.out.get()));
- String storiesFileName = settings.storiesFileName;
-
- String depFileName = settings.depFileName;
- if (depFileName == null) {
- depFileName = "";
+ try {
+ Map<String, String> permInfo = readPermutationInfo(settings);
+ SoycDashboard dashboard = new SoycDashboard(outDir);
+ for (String permutationId : permInfo.keySet()) {
+ dashboard.startNewPermutation(permutationId);
+ if (settings.symbolMapsDir.get() == null) {
+ dashboard.readFromFilesNamed(settings.storiesFileName,
+ settings.depFileName, settings.splitPointsFileName);
+ } else {
+ String soycDir = settings.soycDir.get();
+ dashboard.readFromFilesNamed(soycInputFile(soycDir, "stories",
+ permutationId), soycInputFile(soycDir, "dependencies",
+ permutationId), soycInputFile(soycDir, "splitPoints",
+ permutationId));
}
- String splitPointsFileName = settings.splitPointsFileName;
- if (splitPointsFileName == null) {
- splitPointsFileName = "";
- }
-
- if (settings.symbolMapsDir.get() != null) {
- storiesFileName = settings.soycDir.get() + "/stories" + permutationId
- + ".xml.gz";
-
- if (!(new File(storiesFileName).exists())) {
- storiesFileName = settings.soycDir.get() + "/stories"
- + permutationId + ".xml";
- }
- depFileName = settings.soycDir.get() + "/dependencies"
- + permutationId + ".xml.gz";
- if (!(new File(depFileName).exists())) {
- depFileName = settings.soycDir.get() + "/dependencies"
- + permutationId + ".xml";
- }
- splitPointsFileName = settings.soycDir.get() + "/splitPoints"
- + permutationId + ".xml.gz";
- if (!(new File(splitPointsFileName).exists())) {
- splitPointsFileName = settings.soycDir.get() + "/splitPoints"
- + permutationId + ".xml";
- }
- }
-
- settings.displayDependencies = (new File(depFileName)).exists();
- settings.displaySplitPoints = (new File(splitPointsFileName)).exists();
-
- new File(settings.out.get()).mkdir();
- if (settings.displayDependencies) {
- /**
- * handle dependencies
- */
- Map<String, Map<String, String>> dependencies = new TreeMap<String, Map<String, String>>();
- DefaultHandler depHandler = parseXMLDocumentDependencies(dependencies);
- SAXParserFactory depFactoryMain = SAXParserFactory.newInstance();
- depFactoryMain.setNamespaceAware(true);
- SAXParser saxParser = depFactoryMain.newSAXParser();
- InputStream in = new FileInputStream(depFileName);
- if (depFileName.endsWith(".gz")) {
- in = new GZIPInputStream(in);
- }
- in = new BufferedInputStream(in);
- saxParser.parse(in, depHandler);
-
- makeTopLevelHtmlForPerm.makeDependenciesHtml(dependencies,
- permutationId);
- }
-
- if (settings.displaySplitPoints) {
- /**
- * handle runAsync split points
- */
-
- DefaultHandler splitPointHandler = parseXMLDocumentSplitPoints(globalInformation);
- SAXParserFactory splitPointsFactoryMain = SAXParserFactory.newInstance();
- splitPointsFactoryMain.setNamespaceAware(true);
-
- SAXParser saxParser = splitPointsFactoryMain.newSAXParser();
- InputStream in = new FileInputStream(splitPointsFileName);
- if (depFileName.endsWith(".gz")) {
- in = new GZIPInputStream(in);
- }
- in = new BufferedInputStream(in);
- saxParser.parse(in, splitPointHandler);
- }
-
- /**
- * handle everything else
- */
-
- DefaultHandler handler = parseXMLDocumentSizeMap(globalInformation);
- SAXParserFactory factoryMain = SAXParserFactory.newInstance();
- factoryMain.setNamespaceAware(true);
- SAXParser saxParser = factoryMain.newSAXParser();
- InputStream in = new FileInputStream(storiesFileName);
- if (storiesFileName.endsWith(".gz")) {
- in = new GZIPInputStream(in);
- }
- in = new BufferedInputStream(in);
- saxParser.parse(in, handler);
-
- // add to "All Other Code" if none of the special categories apply
- for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
- updateAllOtherCodeType(breakdown.nameToCodeColl, globalInformation);
- }
- globalInformation.computePackageSizes();
-
- // clean up the RPC categories
- for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
- foldInRPCHeuristic(breakdown.nameToCodeColl);
- }
-
- // generate all the html files
- makeTopLevelHtmlForPerm.makeSplitStatusPages(permutationId);
- makeTopLevelHtmlForPerm.makeLeftoverStatusPages(permutationId);
- for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
- DependencyLinker linker = chooseDependencyLinker(
- makeTopLevelHtmlForPerm, breakdown);
- makeHTMLFiles(makeTopLevelHtmlForPerm, breakdown, linker,
- permutationId);
- }
+ dashboard.generateForOnePermutation();
System.out.println("Finished creating reports for permutation.");
}
- System.out.println("Finished creating reports. To see the dashboard, open index.html in your browser.");
+ dashboard.generateCrossPermutationFiles(permInfo);
+ System.out.println("Finished creating reports. To see the dashboard, open index.html in your browser.");
} catch (ParserConfigurationException e) {
System.err.println("Could not parse document. " + e.getMessage());
System.exit(1);
@@ -204,45 +119,21 @@
} catch (IOException e) {
System.err.println("Error creating html file. " + e.getMessage());
System.exit(1);
- } catch (Settings.ArgumentListException e) {
- System.err.println(e.getMessage());
- System.err.println("Usage: "
- + "java com.google.gwt.soyc.SoycDashboard -resources dir -soycDir dir -symbolMaps dir [-out dir]");
- System.err.println("(Legacy usage: "
- + "java com.google.gwt.soyc.SoycDashboard options stories0.xml[.gz] [dependencies0.xml[.gz]] [splitpoints0.xml[.gz]])");
- System.err.println("Options:");
- System.err.println(Settings.settingsHelp());
- System.exit(1);
}
}
- private static Collection<SizeBreakdown> breakdownsForFragment(
- Integer fragment, GlobalInformation globalInformation) {
- List<SizeBreakdown> breakdowns = new ArrayList<SizeBreakdown>();
- breakdowns.add(globalInformation.getTotalCodeBreakdown());
- if (fragment == 0) {
- breakdowns.add(globalInformation.getInitialCodeBreakdown());
+ /**
+ * Open a file for reading. If the filename ends in .gz, then wrap the stream
+ * with a {@link GZIPInputStream}.
+ */
+ public static InputStream openPossiblyGzippedFile(String filename)
+ throws IOException {
+ InputStream in = new FileInputStream(filename);
+ if (filename.endsWith(".gz")) {
+ in = new GZIPInputStream(in);
}
- if (fragment == (globalInformation.getNumSplitPoints() + 1)) {
- breakdowns.add(globalInformation.getLeftoversBreakdown());
- }
- if (fragment >= 1 && fragment <= globalInformation.getNumSplitPoints()) {
- breakdowns.add(globalInformation.splitPointCodeBreakdown(fragment));
- }
- return breakdowns;
- }
-
- private static DependencyLinker chooseDependencyLinker(
- MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm, SizeBreakdown breakdown) {
- if (breakdown == makeTopLevelHtmlForPerm.getGlobalInformation().getTotalCodeBreakdown()) {
- return makeTopLevelHtmlForPerm.new DependencyLinkerForTotalBreakdown();
- } else if (breakdown == makeTopLevelHtmlForPerm.getGlobalInformation().getInitialCodeBreakdown()) {
- return makeTopLevelHtmlForPerm.new DependencyLinkerForInitialCode();
- } else if (breakdown == makeTopLevelHtmlForPerm.getGlobalInformation().getLeftoversBreakdown()) {
- return makeTopLevelHtmlForPerm.new DependencyLinkerForLeftoversFragment();
- } else {
- return makeTopLevelHtmlForPerm.new DependencyLinkerForExclusiveFragment();
- }
+ in = new BufferedInputStream(in);
+ return in;
}
/*
@@ -279,27 +170,6 @@
}
}
- /**
- * Generates all the HTML files for one size breakdown.
- *
- * @param makeTopLevelHtmlForPerm
- * @param breakdown
- * @param depLinker
- * @param permutationId
- * @throws IOException
- */
- private static void makeHTMLFiles(
- MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm, SizeBreakdown breakdown,
- DependencyLinker depLinker, String permutationId) throws IOException {
- makeTopLevelHtmlForPerm.makePackageClassesHtmls(breakdown, depLinker,
- permutationId);
- makeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(breakdown, permutationId);
- makeTopLevelHtmlForPerm.makeLiteralsClassesTableHtmls(breakdown,
- permutationId);
- makeTopLevelHtmlForPerm.makeBreakdownShell(breakdown, permutationId);
- makeTopLevelHtmlForPerm.makeTopLevelShell(permutationId);
- }
-
private static DefaultHandler parseXMLDocumentDependencies(
final Map<String, Map<String, String>> allDependencies) {
DefaultHandler handler = new DefaultHandler() {
@@ -357,7 +227,193 @@
return handler;
}
- private static DefaultHandler parseXMLDocumentSizeMap(
+ private static Map<String, String> readPermutationInfo(Settings settings)
+ throws FileNotFoundException {
+ Map<String, String> allPermsInfo = new TreeMap<String, String>();
+ if (settings.symbolMapsDir.get() == null) {
+ String permutationId = settings.storiesFileName;
+ permutationId = permutationId.replaceAll(".*/stories", "");
+ permutationId = permutationId.replaceAll("\\.xml(\\.gz)?", "");
+ allPermsInfo.put(permutationId, "");
+ } else {
+ File dir = new File(settings.symbolMapsDir.get());
+ String files[] = dir.list();
+ for (Integer i = 0; i < files.length; i++) {
+ String permFileName = settings.symbolMapsDir.get() + "/" + files[i];
+ FileReader fir = new FileReader(permFileName);
+
+ Scanner sc = new Scanner(fir);
+
+ String permutationId = "";
+ String permutationInfo = "";
+ int lineCount = 0;
+ while ((sc.hasNextLine()) && (lineCount < 2)) {
+
+ String curLine = sc.nextLine();
+ curLine = curLine.trim();
+
+ if (curLine.startsWith("# {")) {
+ curLine = curLine.replace("# {", "");
+ curLine = curLine.replace("}", "");
+ curLine = curLine.trim();
+ if (lineCount == 0) {
+ permutationId = curLine;
+ } else {
+ permutationInfo = curLine;
+ }
+ lineCount++;
+ }
+ }
+ allPermsInfo.put(permutationId, permutationInfo);
+ }
+ }
+ return allPermsInfo;
+ }
+
+ private static String soycInputFile(String soycDir, String baseName,
+ String permutationId) {
+ String name = soycDir + "/" + baseName + permutationId + ".xml.gz";
+ if (new File(name).exists()) {
+ return name;
+ }
+ return soycDir + "/" + baseName + permutationId + ".xml";
+ }
+
+ /**
+ * Global information for the current permutation being emitted.
+ */
+ private GlobalInformation globalInformation;
+
+ /**
+ * HTML emitter for the current permutation being emitted.
+ */
+ private MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm;
+
+ private final OutputDirectory outDir;
+
+ public SoycDashboard(OutputDirectory outDir) {
+ this.outDir = outDir;
+ }
+
+ public void generateCrossPermutationFiles(Map<String, String> permInfo)
+ throws IOException {
+ StaticResources.emit(outDir);
+ MakeTopLevelHtmlForPerm.makeTopLevelHtmlForAllPerms(permInfo, outDir);
+ }
+
+ public void generateForOnePermutation() throws IOException {
+ if (globalInformation.dependencies != null) {
+ makeTopLevelHtmlForPerm.makeDependenciesHtml();
+ }
+
+ if (globalInformation.getNumSplitPoints() > 0) {
+ makeTopLevelHtmlForPerm.makeSplitStatusPages();
+ makeTopLevelHtmlForPerm.makeLeftoverStatusPages();
+ }
+ for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
+ DependencyLinker linker = chooseDependencyLinker(breakdown);
+ makeHTMLFiles(makeTopLevelHtmlForPerm, breakdown, linker);
+ }
+ }
+
+ public void readDependencies(InputStream stream)
+ throws ParserConfigurationException, SAXException, IOException {
+ globalInformation.dependencies = new TreeMap<String, Map<String, String>>();
+ DefaultHandler depHandler = parseXMLDocumentDependencies(globalInformation.dependencies);
+ SAXParserFactory depFactoryMain = SAXParserFactory.newInstance();
+ depFactoryMain.setNamespaceAware(true);
+ SAXParser saxParser = depFactoryMain.newSAXParser();
+ saxParser.parse(stream, depHandler);
+ }
+
+ public void readSizeMaps(InputStream stream)
+ throws ParserConfigurationException, SAXException, IOException {
+ DefaultHandler handler = parseXMLDocumentSizeMap(globalInformation);
+ SAXParserFactory factoryMain = SAXParserFactory.newInstance();
+ factoryMain.setNamespaceAware(true);
+ SAXParser saxParser = factoryMain.newSAXParser();
+ saxParser.parse(stream, handler);
+
+ // Now clean up the information that has been read in various ways
+ globalInformation.computePackageSizes();
+
+ // add to "All Other Code" if none of the special categories apply
+ for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
+ updateAllOtherCodeType(breakdown.nameToCodeColl);
+ }
+
+ // clean up the RPC categories
+ for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
+ foldInRPCHeuristic(breakdown.nameToCodeColl);
+ }
+ }
+
+ public void readSplitPoints(InputStream stream)
+ throws ParserConfigurationException, SAXException, IOException {
+ DefaultHandler splitPointHandler = parseXMLDocumentSplitPoints();
+ SAXParserFactory splitPointsFactoryMain = SAXParserFactory.newInstance();
+ splitPointsFactoryMain.setNamespaceAware(true);
+
+ SAXParser saxParser = splitPointsFactoryMain.newSAXParser();
+ saxParser.parse(stream, splitPointHandler);
+ }
+
+ public void startNewPermutation(String permutationId) {
+ globalInformation = new GlobalInformation(permutationId);
+ makeTopLevelHtmlForPerm = new MakeTopLevelHtmlForPerm(globalInformation,
+ outDir);
+ }
+
+ private Collection<SizeBreakdown> breakdownsForFragment(Integer fragment) {
+ List<SizeBreakdown> breakdowns = new ArrayList<SizeBreakdown>();
+ breakdowns.add(globalInformation.getTotalCodeBreakdown());
+ if (fragment == 0) {
+ breakdowns.add(globalInformation.getInitialCodeBreakdown());
+ }
+ if (fragment == (globalInformation.getNumSplitPoints() + 1)) {
+ breakdowns.add(globalInformation.getLeftoversBreakdown());
+ }
+ if (fragment >= 1 && fragment <= globalInformation.getNumSplitPoints()) {
+ breakdowns.add(globalInformation.splitPointCodeBreakdown(fragment));
+ }
+ return breakdowns;
+ }
+
+ private DependencyLinker chooseDependencyLinker(SizeBreakdown breakdown) {
+ if (globalInformation.dependencies == null) {
+ // no dependencies are available
+ return new NullDependencyLinker();
+ }
+
+ if (breakdown == globalInformation.getTotalCodeBreakdown()) {
+ if (globalInformation.getNumSplitPoints() > 0) {
+ return makeTopLevelHtmlForPerm.new DependencyLinkerForTotalBreakdown();
+ } else {
+ return makeTopLevelHtmlForPerm.new DependencyLinkerForInitialCode();
+ }
+ } else if (breakdown == globalInformation.getInitialCodeBreakdown()) {
+ return makeTopLevelHtmlForPerm.new DependencyLinkerForInitialCode();
+ } else if (breakdown == globalInformation.getLeftoversBreakdown()) {
+ assert globalInformation.getNumSplitPoints() > 0;
+ return makeTopLevelHtmlForPerm.new DependencyLinkerForLeftoversFragment();
+ } else {
+ return new NullDependencyLinker();
+ }
+ }
+
+ /**
+ * Generates all the HTML files for one size breakdown.
+ */
+ private void makeHTMLFiles(MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm,
+ SizeBreakdown breakdown, DependencyLinker depLinker) throws IOException {
+ makeTopLevelHtmlForPerm.makePackageClassesHtmls(breakdown, depLinker);
+ makeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(breakdown);
+ makeTopLevelHtmlForPerm.makeLiteralsClassesTableHtmls(breakdown);
+ makeTopLevelHtmlForPerm.makeBreakdownShell(breakdown);
+ makeTopLevelHtmlForPerm.makeTopLevelShell();
+ }
+
+ private DefaultHandler parseXMLDocumentSizeMap(
final GlobalInformation globalInformation) {
return new DefaultHandler() {
int fragment = -1;
@@ -393,8 +449,7 @@
} catch (NumberFormatException e) {
throw new FormatException(e);
}
- for (SizeBreakdown breakdown : breakdownsForFragment(fragment,
- globalInformation)) {
+ for (SizeBreakdown breakdown : breakdownsForFragment(fragment)) {
breakdown.sizeAllCode += size;
}
} else if (localName.compareTo("size") == 0) {
@@ -491,17 +546,14 @@
private void recordSize(String refType, String ref, int size,
GlobalInformation globalInformation) {
- for (SizeBreakdown breakdown : breakdownsForFragment(fragment,
- globalInformation)) {
+ for (SizeBreakdown breakdown : breakdownsForFragment(fragment)) {
accountForSize(breakdown, refType, ref, size, globalInformation);
}
}
};
}
- private static DefaultHandler parseXMLDocumentSplitPoints(
- final GlobalInformation globalInformation) {
-
+ private DefaultHandler parseXMLDocumentSplitPoints() {
DefaultHandler handler = new DefaultHandler() {
private boolean inInitialLoadSequence = false;
@@ -558,12 +610,25 @@
return handler;
}
+ private void readFromFilesNamed(String storiesFileName,
+ String dependenciesFileName, String splitPointsFileName)
+ throws ParserConfigurationException, SAXException, IOException {
+ if (dependenciesFileName != null && new File(dependenciesFileName).exists()) {
+ readDependencies(openPossiblyGzippedFile(dependenciesFileName));
+ }
+
+ if (splitPointsFileName != null && new File(splitPointsFileName).exists()) {
+ readSplitPoints(openPossiblyGzippedFile(splitPointsFileName));
+ }
+
+ readSizeMaps(openPossiblyGzippedFile(storiesFileName));
+ }
+
/*
* assigns code to "all other code" if none of the special categories apply
*/
- private static void updateAllOtherCodeType(
- final HashMap<String, CodeCollection> nameToCodeColl,
- GlobalInformation globalInformation) {
+ private void updateAllOtherCodeType(
+ final HashMap<String, CodeCollection> nameToCodeColl) {
// all classes not in any of the other categories
for (String className : globalInformation.getClassToPackage().keySet()) {
if ((!nameToCodeColl.get("widget").classes.contains(className))
@@ -576,5 +641,4 @@
}
}
}
-
}
diff --git a/dev/core/src/com/google/gwt/soyc/StaticResources.java b/dev/core/src/com/google/gwt/soyc/StaticResources.java
new file mode 100644
index 0000000..5e63e6c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/soyc/StaticResources.java
@@ -0,0 +1,61 @@
+/*
+ * 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.soyc;
+
+import com.google.gwt.soyc.io.OutputDirectory;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This class handles static resources such as CSS and GIF files that support
+ * the generated HTML. The resources are expected to be available via this
+ * class's class loader.
+ */
+public class StaticResources {
+ /**
+ * A list of all static resources. Storing it this way allows the resources to
+ * be loaded via a Java class loader, which is often convenient. Class loaders
+ * cannot be iterated over.
+ */
+ private static String[] resourceNames = new String[] {
+ "classLevel.css", "common.css", "roundedCorners.css", "images/1bl.gif",
+ "images/1br.gif", "images/1tl.gif", "images/1tr.gif", "images/bb.gif",
+ "images/blc.gif", "images/brc.gif", "images/l.gif", "images/r.gif",
+ "images/roundedbox_lo.gif", "images/roundedbox_lu.gif",
+ "images/roundedbox_ro.gif", "images/roundedbox_ru.gif", "images/tb.gif",
+ "images/tlc.gif", "images/trc.gif",};
+
+ public static void emit(OutputDirectory outDir) throws IOException {
+ String prefix = StaticResources.class.getPackage().getName().replace('.',
+ '/')
+ + "/resources/";
+ ClassLoader loader = StaticResources.class.getClassLoader();
+ for (String resourceName : resourceNames) {
+ InputStream in = loader.getResourceAsStream(prefix + resourceName);
+ if (in == null) {
+ throw new Error("Could not find resource via my class loader: "
+ + resourceName);
+ }
+ OutputStream out = outDir.getOutputStream(resourceName);
+ Utility.streamOut(in, out, 10240);
+ in.close();
+ out.close();
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/soyc/io/ArtifactsOutputDirectory.java b/dev/core/src/com/google/gwt/soyc/io/ArtifactsOutputDirectory.java
new file mode 100644
index 0000000..fb774b7
--- /dev/null
+++ b/dev/core/src/com/google/gwt/soyc/io/ArtifactsOutputDirectory.java
@@ -0,0 +1,87 @@
+/*
+ * 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.soyc.io;
+
+import com.google.gwt.core.ext.linker.impl.StandardCompilationAnalysis.SoycArtifact;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An {@link OutputDirectory} that writes its output as a list of GWT compiler
+ * artifacts.
+ */
+public class ArtifactsOutputDirectory implements OutputDirectory {
+ /**
+ * An in-memory output stream. When it is closed, its contents are saved to an
+ * artifact.
+ */
+ private class OutputStreamForArtifact extends OutputStream {
+ private static final String OUTPUT_DIRECTORY_NAME = "compile-report";
+
+ private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ private boolean closed = false;
+ private final String path;
+
+ public OutputStreamForArtifact(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public void close() {
+ if (!closed) {
+ closed = true;
+ SoycArtifact newArtifact = new SoycArtifact(OUTPUT_DIRECTORY_NAME + "/"
+ + path, baos.toByteArray());
+ newArtifact.setPrivate(false);
+ artifacts.add(newArtifact);
+ baos = null;
+ }
+ }
+
+ @Override
+ public void write(byte b[]) throws IOException {
+ baos.write(b);
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ baos.write(b, off, len);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ baos.write(b);
+ }
+ }
+
+ private List<SoycArtifact> artifacts = new ArrayList<SoycArtifact>();
+
+ /**
+ * Return the list of artifacts that have been written so far.
+ */
+ public List<SoycArtifact> getArtifacts() {
+ return artifacts;
+ }
+
+ public OutputStream getOutputStream(String path) throws IOException {
+ return new OutputStreamForArtifact(path);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/soyc/io/FileSystemOutputDirectory.java b/dev/core/src/com/google/gwt/soyc/io/FileSystemOutputDirectory.java
new file mode 100644
index 0000000..6914c00
--- /dev/null
+++ b/dev/core/src/com/google/gwt/soyc/io/FileSystemOutputDirectory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.soyc.io;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An {@link OutputDirectory} that writes directly to the file system.
+ */
+public class FileSystemOutputDirectory implements OutputDirectory {
+ private final File outDir;
+
+ public FileSystemOutputDirectory(File outDir) {
+ this.outDir = outDir;
+ }
+
+ public OutputStream getOutputStream(String path) throws IOException {
+ File outFile = new File(outDir, path);
+ outFile.getParentFile().mkdirs();
+ return new FileOutputStream(outFile);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/soyc/io/OutputDirectory.java b/dev/core/src/com/google/gwt/soyc/io/OutputDirectory.java
new file mode 100644
index 0000000..e80777d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/soyc/io/OutputDirectory.java
@@ -0,0 +1,28 @@
+/*
+ * 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.soyc.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An abstraction over output directories. The SOYC dashboard writes to this
+ * interface so that it can, depending on how it is invoked, both write to the
+ * filesystem and generate GWT compiler artifacts.
+ */
+public interface OutputDirectory {
+ OutputStream getOutputStream(String path) throws IOException;
+}
diff --git a/tools/soyc-vis/classLevel.css b/dev/core/src/com/google/gwt/soyc/resources/classLevel.css
similarity index 100%
rename from tools/soyc-vis/classLevel.css
rename to dev/core/src/com/google/gwt/soyc/resources/classLevel.css
diff --git a/tools/soyc-vis/common.css b/dev/core/src/com/google/gwt/soyc/resources/common.css
similarity index 100%
rename from tools/soyc-vis/common.css
rename to dev/core/src/com/google/gwt/soyc/resources/common.css
diff --git a/tools/soyc-vis/images/1bl.gif b/dev/core/src/com/google/gwt/soyc/resources/images/1bl.gif
similarity index 100%
rename from tools/soyc-vis/images/1bl.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/1bl.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1br.gif b/dev/core/src/com/google/gwt/soyc/resources/images/1br.gif
similarity index 100%
rename from tools/soyc-vis/images/1br.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/1br.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1tl.gif b/dev/core/src/com/google/gwt/soyc/resources/images/1tl.gif
similarity index 100%
rename from tools/soyc-vis/images/1tl.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/1tl.gif
Binary files differ
diff --git a/tools/soyc-vis/images/1tr.gif b/dev/core/src/com/google/gwt/soyc/resources/images/1tr.gif
similarity index 100%
rename from tools/soyc-vis/images/1tr.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/1tr.gif
Binary files differ
diff --git a/tools/soyc-vis/images/bb.gif b/dev/core/src/com/google/gwt/soyc/resources/images/bb.gif
similarity index 100%
rename from tools/soyc-vis/images/bb.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/bb.gif
Binary files differ
diff --git a/tools/soyc-vis/images/blc.gif b/dev/core/src/com/google/gwt/soyc/resources/images/blc.gif
similarity index 100%
rename from tools/soyc-vis/images/blc.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/blc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/brc.gif b/dev/core/src/com/google/gwt/soyc/resources/images/brc.gif
similarity index 100%
rename from tools/soyc-vis/images/brc.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/brc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/l.gif b/dev/core/src/com/google/gwt/soyc/resources/images/l.gif
similarity index 100%
rename from tools/soyc-vis/images/l.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/l.gif
Binary files differ
diff --git a/tools/soyc-vis/images/r.gif b/dev/core/src/com/google/gwt/soyc/resources/images/r.gif
similarity index 100%
rename from tools/soyc-vis/images/r.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/r.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_lo.gif b/dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_lo.gif
similarity index 100%
rename from tools/soyc-vis/images/roundedbox_lo.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_lo.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_lu.gif b/dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_lu.gif
similarity index 100%
rename from tools/soyc-vis/images/roundedbox_lu.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_lu.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_ro.gif b/dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_ro.gif
similarity index 100%
rename from tools/soyc-vis/images/roundedbox_ro.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_ro.gif
Binary files differ
diff --git a/tools/soyc-vis/images/roundedbox_ru.gif b/dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_ru.gif
similarity index 100%
rename from tools/soyc-vis/images/roundedbox_ru.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/roundedbox_ru.gif
Binary files differ
diff --git a/tools/soyc-vis/images/tb.gif b/dev/core/src/com/google/gwt/soyc/resources/images/tb.gif
similarity index 100%
rename from tools/soyc-vis/images/tb.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/tb.gif
Binary files differ
diff --git a/tools/soyc-vis/images/tlc.gif b/dev/core/src/com/google/gwt/soyc/resources/images/tlc.gif
similarity index 100%
rename from tools/soyc-vis/images/tlc.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/tlc.gif
Binary files differ
diff --git a/tools/soyc-vis/images/trc.gif b/dev/core/src/com/google/gwt/soyc/resources/images/trc.gif
similarity index 100%
rename from tools/soyc-vis/images/trc.gif
rename to dev/core/src/com/google/gwt/soyc/resources/images/trc.gif
Binary files differ
diff --git a/tools/soyc-vis/roundedCorners.css b/dev/core/src/com/google/gwt/soyc/resources/roundedCorners.css
similarity index 100%
rename from tools/soyc-vis/roundedCorners.css
rename to dev/core/src/com/google/gwt/soyc/resources/roundedCorners.css
diff --git a/plugins/ie/oophm/oophm/oophm.vcproj b/plugins/ie/oophm/oophm/oophm.vcproj
index a0cae8c..288d48c 100644
--- a/plugins/ie/oophm/oophm/oophm.vcproj
+++ b/plugins/ie/oophm/oophm/oophm.vcproj
@@ -56,7 +56,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="../../../common"
+ AdditionalIncludeDirectories=""$(ProjectDir)";../../../platform/Win;../../../common"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;GWT_DEBUGLEVEL=Spam"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -151,7 +151,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="../../../common"
+ AdditionalIncludeDirectories=""$(ProjectDir)";../../../platform/Win;../../../common"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;GWT_DEBUGLEVEL=Spam"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -342,7 +342,7 @@
Name="VCCLCompilerTool"
Optimization="2"
FavorSizeOrSpeed="1"
- AdditionalIncludeDirectories="../../../platform/Win;../../../common"
+ AdditionalIncludeDirectories=""$(ProjectDir)";../../../platform/Win;../../../common"
PreprocessorDefinitions="_WINDOWS;GWT_DEBUGDISABLE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
diff --git a/plugins/ie/oophm/oophm/plugin.cpp b/plugins/ie/oophm/oophm/plugin.cpp
index a372cdf..d48dc7d 100644
--- a/plugins/ie/oophm/oophm/plugin.cpp
+++ b/plugins/ie/oophm/oophm/plugin.cpp
@@ -92,7 +92,12 @@
return S_OK;
}
- std::string tabKey = ""; // TODO(jat): add support for tab identity
+ // Use the current thread ID as a proxy for tab ID.
+ DWORD threadId = GetCurrentThreadId();
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%lu", threadId);
+ std::string tabKey = buf;
+
std::string sessionKey = BSTRToUTF8(bsessionKey);
std::string moduleName = BSTRToUTF8(bmoduleName);
IOmNavigator* navigator;
diff --git a/plugins/ie/prebuilt/oophm.dll b/plugins/ie/prebuilt/oophm.dll
old mode 100644
new mode 100755
index ca398aa..f2aac8a
--- a/plugins/ie/prebuilt/oophm.dll
+++ b/plugins/ie/prebuilt/oophm.dll
Binary files differ
diff --git a/plugins/ie/prebuilt/oophm64.dll b/plugins/ie/prebuilt/oophm64.dll
old mode 100644
new mode 100755
Binary files differ
diff --git a/tools/soyc-vis/build.xml b/tools/soyc-vis/build.xml
index 51b8833..24274b4 100644
--- a/tools/soyc-vis/build.xml
+++ b/tools/soyc-vis/build.xml
@@ -13,13 +13,9 @@
</target>
<target name="compile">
- <mkdir dir="${javac.out}/com/google/gwt/soyc/resources/images"/>
- <copy todir="${javac.out}/com/google/gwt/soyc/resources/images">
- <fileset dir="images"/>
+ <copy todir="${javac.out}/com/google/gwt/soyc/resources">
+ <fileset dir="${gwt.root}/dev/core/src/com/google/gwt/soyc/resources"/>
</copy>
- <copy file="classLevel.css" tofile="${javac.out}/com/google/gwt/soyc/resources/classLevel.css"/>
- <copy file="roundedCorners.css" tofile="${javac.out}/com/google/gwt/soyc/resources/roundedCorners.css"/>
- <copy file="common.css" tofile="${javac.out}/com/google/gwt/soyc/resources/common.css"/>
</target>
<target name="build" depends="compile">
diff --git a/user/javadoc/com/google/gwt/examples/AsyncJUnitExample.java b/user/javadoc/com/google/gwt/examples/AsyncJUnitExample.java
index fb73afb..275ff84 100644
--- a/user/javadoc/com/google/gwt/examples/AsyncJUnitExample.java
+++ b/user/javadoc/com/google/gwt/examples/AsyncJUnitExample.java
@@ -30,6 +30,11 @@
* Tests the Timer class asynchronously.
*/
public void testTimer() {
+
+ // Set a delay period significantly longer than the
+ // event is expected to take.
+ delayTestFinish(500);
+
// Setup an asynchronous event handler.
Timer timer = new Timer() {
@Override
@@ -41,10 +46,6 @@
}
};
- // Set a delay period significantly longer than the
- // event is expected to take.
- delayTestFinish(500);
-
// Schedule the event and return control to the test system.
timer.schedule(100);
}
diff --git a/user/src/com/google/gwt/junit/BatchingStrategy.java b/user/src/com/google/gwt/junit/BatchingStrategy.java
index 1932854..14a5a11 100644
--- a/user/src/com/google/gwt/junit/BatchingStrategy.java
+++ b/user/src/com/google/gwt/junit/BatchingStrategy.java
@@ -19,6 +19,7 @@
import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -37,6 +38,24 @@
* @return an ordered list of test blocks to run
*/
public abstract List<TestInfo[]> getTestBlocks(String syntheticModuleName);
+
+ /**
+ * Get the set of tests for this module, minus tests that should not be
+ * executed.
+ *
+ * @return the set of tests to execute
+ */
+ protected final Set<TestInfo> getTestsForModule(String syntheticModuleName) {
+ Set<TestInfo> toExecute = GWTTestCase.getTestsForModule(syntheticModuleName).getTests();
+ Set<TestInfo> toRemove = new HashSet<TestInfo>();
+ for (TestInfo info : toExecute) {
+ if (JUnitShell.mustNotExecuteTest(info)) {
+ toRemove.add(info);
+ }
+ }
+ toExecute.removeAll(toRemove);
+ return toExecute;
+ }
}
/**
@@ -46,8 +65,7 @@
class NoBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
for (TestInfo testInfo : allTestsInModule) {
testBlocks.add(new TestInfo[] {testInfo});
@@ -62,8 +80,7 @@
class ClassBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
String lastTestClass = null;
List<TestInfo> lastTestBlock = null;
@@ -96,11 +113,12 @@
class ModuleBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
- TestInfo[] testBlock = allTestsInModule.toArray(new TestInfo[allTestsInModule.size()]);
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
- testBlocks.add(testBlock);
+ if (allTestsInModule.size() > 0) {
+ TestInfo[] testBlock = allTestsInModule.toArray(new TestInfo[allTestsInModule.size()]);
+ testBlocks.add(testBlock);
+ }
return testBlocks;
}
}
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 59bf1e6..6158789 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -396,19 +396,34 @@
* @return the list of remote user agents
*/
public static String[] getRemoteUserAgents() {
- return getUnitTestShell().remoteUserAgents;
+ if (unitTestShell == null) {
+ return null;
+ }
+ return unitTestShell.remoteUserAgents;
}
/**
* Checks if a testCase should not be executed. Currently, a test is either
* executed on all clients (mentioned in this test) or on no clients.
*
- * @param testCase current testCase.
+ * @param testInfo the test info to check
* @return true iff the test should not be executed on any of the specified
* clients.
*/
- public static boolean mustNotExecuteTest(TestCase testCase) {
- return getUnitTestShell().mustNotExecuteTest(getBannedPlatforms(testCase));
+ public static boolean mustNotExecuteTest(TestInfo testInfo) {
+ if (unitTestShell == null) {
+ throw new IllegalStateException(
+ "mustNotExecuteTest cannot be called before runTest()");
+ }
+ try {
+ Class<?> testClass = TestCase.class.getClassLoader().loadClass(
+ testInfo.getTestClass());
+ return unitTestShell.mustNotExecuteTest(getBannedPlatforms(testClass,
+ testInfo.getTestMethod()));
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Could not load test class: "
+ + testInfo.getTestClass());
+ }
}
/**
@@ -488,16 +503,19 @@
}
/**
- * returns the set of banned {@code Platform} for a test method.
+ * Returns the set of banned {@code Platform} for a test method.
+ *
+ * @param testClass the testClass
+ * @param methodName the name of the test method
*/
- private static Set<Platform> getBannedPlatforms(TestCase testCase) {
- Class<?> testClass = testCase.getClass();
+ private static Set<Platform> getBannedPlatforms(Class<?> testClass,
+ String methodName) {
Set<Platform> bannedSet = EnumSet.noneOf(Platform.class);
if (testClass.isAnnotationPresent(DoNotRunWith.class)) {
bannedSet.addAll(Arrays.asList(testClass.getAnnotation(DoNotRunWith.class).value()));
}
try {
- Method testMethod = testClass.getMethod(testCase.getName());
+ Method testMethod = testClass.getMethod(methodName);
if (testMethod.isAnnotationPresent(DoNotRunWith.class)) {
bannedSet.addAll(Arrays.asList(testMethod.getAnnotation(
DoNotRunWith.class).value()));
@@ -536,6 +554,10 @@
// TODO: install a shutdown hook? Not necessary with GWTShell.
unitTestShell.lastLaunchFailed = false;
}
+ if (unitTestShell.thread != Thread.currentThread()) {
+ throw new IllegalThreadStateException(
+ "JUnitShell can only be accessed from the thread that created it.");
+ }
return unitTestShell;
}
@@ -641,10 +663,16 @@
private long testMethodTimeout;
/**
+ * The thread that created the JUnitShell.
+ */
+ private Thread thread;
+
+ /**
* Enforce the singleton pattern. The call to {@link GWTShell}'s ctor forces
* server mode and disables processing extra arguments as URLs to be shown.
*/
private JUnitShell() {
+ thread = Thread.currentThread();
setRunTomcat(true);
setHeadless(true);
}
@@ -900,7 +928,8 @@
private void runTestImpl(GWTTestCase testCase, TestResult testResult)
throws UnableToCompleteException {
- if (mustNotExecuteTest(testCase)) {
+ if (mustNotExecuteTest(getBannedPlatforms(testCase.getClass(),
+ testCase.getName()))) {
return;
}
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 4ad6866..176c8a0 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -273,11 +273,6 @@
public void setName(String name) {
super.setName(name);
- // If we can't run this test, don't add it to the map of all tests to batch.
- if (JUnitShell.mustNotExecuteTest(this)) {
- return;
- }
-
synchronized (ALL_GWT_TESTS_LOCK) {
// Once the name is set, we can add ourselves to the global set.
String syntheticModuleName = getSyntheticModuleName();
diff --git a/user/src/com/google/gwt/resources/Resources.gwt.xml b/user/src/com/google/gwt/resources/Resources.gwt.xml
index 1db713a..3c66d64 100644
--- a/user/src/com/google/gwt/resources/Resources.gwt.xml
+++ b/user/src/com/google/gwt/resources/Resources.gwt.xml
@@ -16,6 +16,8 @@
<module>
<!-- Pull in the necessary base support, including user.agent detection -->
<inherits name="com.google.gwt.core.Core" />
+ <!-- Pull in StyleInjector for CssResource -->
+ <inherits name="com.google.gwt.dom.DOM" />
<!-- Used by ExternalTextResource -->
<inherits name="com.google.gwt.http.HTTP" />
diff --git a/user/src/com/google/gwt/resources/client/CssResource.java b/user/src/com/google/gwt/resources/client/CssResource.java
index 908c777..5020448 100644
--- a/user/src/com/google/gwt/resources/client/CssResource.java
+++ b/user/src/com/google/gwt/resources/client/CssResource.java
@@ -285,6 +285,16 @@
}
/**
+ * Calls
+ * {@link com.google.gwt.dom.client.StyleInjector#injectStylesheet(String)} to
+ * inject the contents of the CssResource into the DOM. Repeated calls to this
+ * method on an instance of a CssResources will have no effect.
+ *
+ * @return <code>true</code> if this method mutated the DOM.
+ */
+ boolean ensureInjected();
+
+ /**
* Provides the contents of the CssResource.
*/
String getText();
diff --git a/user/src/com/google/gwt/resources/css/ClassRenamer.java b/user/src/com/google/gwt/resources/css/ClassRenamer.java
new file mode 100644
index 0000000..a78ccbd
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/ClassRenamer.java
@@ -0,0 +1,271 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.resources.client.CssResource.ClassName;
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssDef;
+import com.google.gwt.resources.css.ast.CssSelector;
+import com.google.gwt.resources.css.ast.CssStylesheet;
+import com.google.gwt.resources.css.ast.CssVisitor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+/**
+ * Renames class selectors to their obfuscated names.
+ */
+public class ClassRenamer extends CssVisitor {
+
+ /**
+ * A tag to indicate that an externally-defined CSS class has no JMethod that
+ * is used to access it.
+ */
+ private static final Replacement UNREFERENCED_EXTERNAL = new Replacement(
+ null, null);
+
+ /*
+ * TODO: Replace with Pair<A, B>.
+ */
+ private static class Replacement {
+
+ private JMethod method;
+ private String obfuscatedClassName;
+
+ public Replacement(JMethod method, String obfuscatedClassName) {
+ this.method = method;
+ this.obfuscatedClassName = obfuscatedClassName;
+ }
+
+ public JMethod getMethod() {
+ return method;
+ }
+
+ public String getObfuscatedClassName() {
+ return obfuscatedClassName;
+ }
+
+ /**
+ * For debugging use only.
+ */
+ public String toString() {
+ if (this == UNREFERENCED_EXTERNAL) {
+ return "Unreferenced external class name";
+ } else {
+ return method.getName() + "=" + obfuscatedClassName;
+ }
+ }
+ }
+
+ /**
+ * Records replacements that have actually been performed.
+ */
+ private final Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod, String>();
+ 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 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.strict = strict;
+
+ potentialReplacements = computeReplacements(classReplacementsWithPrefix,
+ externalClasses);
+
+ // Require a definition for all classes in the default namespace
+ assert classReplacementsWithPrefix.containsKey("");
+ missingClasses = new HashSet<JMethod>(
+ classReplacementsWithPrefix.get("").keySet());
+ }
+
+ @Override
+ public void endVisit(CssDef x, Context ctx) {
+ cssDefs.add(x.getKey());
+ }
+
+ @Override
+ public void endVisit(CssSelector x, Context ctx) {
+
+ String sel = x.getSelector();
+ int originalLength = sel.length();
+
+ Matcher ma = CssSelector.CLASS_SELECTOR_PATTERN.matcher(sel);
+ StringBuilder sb = new StringBuilder(originalLength);
+ int start = 0;
+
+ while (ma.find()) {
+ String sourceClassName = ma.group(1);
+
+ Replacement entry = potentialReplacements.get(sourceClassName);
+
+ if (entry == null) {
+ unknownClasses.add(sourceClassName);
+ continue;
+
+ } else if (entry == UNREFERENCED_EXTERNAL) {
+ // An @external without an accessor method. This is OK.
+ continue;
+ }
+
+ JMethod method = entry.getMethod();
+ String obfuscatedClassName = entry.getObfuscatedClassName();
+
+ // Consume the interstitial portion of the original selector
+ sb.append(sel.subSequence(start, ma.start(1)));
+ sb.append(obfuscatedClassName);
+ start = ma.end(1);
+
+ actualReplacements.put(method, obfuscatedClassName);
+ missingClasses.remove(method);
+ }
+
+ if (start != 0) {
+ // Consume the remainder and update the selector
+ sb.append(sel.subSequence(start, originalLength));
+ x.setSelector(sb.toString());
+ }
+ }
+
+ @Override
+ public void endVisit(CssStylesheet x, Context ctx) {
+ boolean stop = false;
+
+ // Skip names corresponding to @def entries. They too can be declared as
+ // String accessors.
+ List<JMethod> toRemove = new ArrayList<JMethod>();
+ for (JMethod method : missingClasses) {
+ if (cssDefs.contains(method.getName())) {
+ toRemove.add(method);
+ }
+ }
+ for (JMethod method : toRemove) {
+ missingClasses.remove(method);
+ }
+
+ if (!missingClasses.isEmpty()) {
+ stop = true;
+ TreeLogger errorLogger = logger.branch(TreeLogger.INFO,
+ "The following obfuscated style classes were missing from "
+ + "the source CSS file:");
+ for (JMethod m : missingClasses) {
+ String name = m.getName();
+ ClassName className = m.getAnnotation(ClassName.class);
+ if (className != null) {
+ name = className.value();
+ }
+ errorLogger.log(TreeLogger.ERROR, name + ": Fix by adding ." + name
+ + "{}");
+ }
+ }
+
+ if (strict && !unknownClasses.isEmpty()) {
+ stop = true;
+ TreeLogger errorLogger = logger.branch(TreeLogger.ERROR,
+ "The following unobfuscated classes were present in a strict CssResource:");
+ for (String s : unknownClasses) {
+ errorLogger.log(TreeLogger.ERROR, s);
+ }
+ errorLogger.log(TreeLogger.INFO, "Fix by adding String accessor "
+ + "method(s) to the CssResource interface for obfuscated classes, "
+ + "or using an @external declaration for unobfuscated classes.");
+ }
+
+ if (stop) {
+ throw new CssCompilerException("Missing a CSS replacement");
+ }
+ }
+
+ /**
+ * Reports the replacements that were actually performed by this visitor.
+ */
+ public Map<JMethod, String> getReplacements() {
+ return actualReplacements;
+ }
+
+ /**
+ * Flatten class name lookups to speed selector rewriting.
+ *
+ * @param classReplacementsWithPrefix a map of local prefixes to the
+ * obfuscated names of imported methods. If a CssResource makes use
+ * of the {@link CssResource.Import} annotation, the keys of this map
+ * will correspond to the {@link CssResource.ImportedWithPrefix}
+ * value defined on the imported CssResource. The zero-length string
+ * key holds the obfuscated names for the CssResource that is being
+ * generated.
+ * @return A flattened version of the classReplacementWithPrefix map, where
+ * the keys are the source class name (with prefix included), and
+ * values have the obfuscated class name and associated JMethod.
+ */
+ private Map<String, Replacement> computeReplacements(
+ Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
+ Set<String> externalClasses) {
+
+ Map<String, Replacement> toReturn = new HashMap<String, Replacement>();
+
+ for (String externalClass : externalClasses) {
+ toReturn.put(externalClass, UNREFERENCED_EXTERNAL);
+ }
+
+ for (Map.Entry<String, Map<JMethod, String>> outerEntry : classReplacementsWithPrefix.entrySet()) {
+ String prefix = outerEntry.getKey();
+
+ for (Map.Entry<JMethod, String> entry : outerEntry.getValue().entrySet()) {
+ JMethod method = entry.getKey();
+ String sourceClassName = method.getName();
+ String obfuscatedClassName = entry.getValue();
+
+ ClassName className = method.getAnnotation(ClassName.class);
+ if (className != null) {
+ sourceClassName = className.value();
+ }
+
+ sourceClassName = prefix + sourceClassName;
+
+ if (externalClasses.contains(sourceClassName)) {
+ /*
+ * It simplifies the sanity-checking logic to treat external classes
+ * as though they were simply obfuscated to exactly the value the user
+ * wants.
+ */
+ obfuscatedClassName = sourceClassName;
+ }
+
+ toReturn.put(sourceClassName, new Replacement(method,
+ obfuscatedClassName));
+ }
+ }
+ return Collections.unmodifiableMap(toReturn);
+ }
+}
diff --git a/user/src/com/google/gwt/resources/css/DefsCollector.java b/user/src/com/google/gwt/resources/css/DefsCollector.java
new file mode 100644
index 0000000..4cb11c8
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/DefsCollector.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssDef;
+import com.google.gwt.resources.css.ast.CssVisitor;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Collects the names of all user-defined {@literal @def} constants in the
+ * stylesheet.
+ */
+public class DefsCollector extends CssVisitor {
+ private final Set<String> defs = new HashSet<String>();
+
+ @Override
+ public void endVisit(CssDef x, Context ctx) {
+ defs.add(x.getKey());
+ }
+
+ public Set<String> getDefs() {
+ return defs;
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/ExternalClassesCollector.java b/user/src/com/google/gwt/resources/css/ExternalClassesCollector.java
new file mode 100644
index 0000000..d6cb7bf
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/ExternalClassesCollector.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssExternalSelectors;
+import com.google.gwt.resources.css.ast.CssVisitor;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Collects all {@code @external} declarations in the stylesheet.
+ */
+public 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;
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/IfEvaluator.java b/user/src/com/google/gwt/resources/css/IfEvaluator.java
new file mode 100644
index 0000000..5e02ad3
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/IfEvaluator.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.ConfigurationProperty;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.SelectionProperty;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssIf;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+import com.google.gwt.resources.css.ast.CssNode;
+
+import java.util.Arrays;
+
+/**
+ * Statically evaluates {@literal @if} rules.
+ */
+public class IfEvaluator extends CssModVisitor {
+ private final TreeLogger logger;
+ private final PropertyOracle oracle;
+
+ public IfEvaluator(TreeLogger logger, PropertyOracle oracle) {
+ this.logger = logger.branch(TreeLogger.DEBUG,
+ "Replacing property-based @if blocks");
+ this.oracle = oracle;
+ }
+
+ @Override
+ public void endVisit(CssIf x, Context ctx) {
+ if (x.getExpression() != null) {
+ // This gets taken care of by the runtime substitution visitor
+ } else {
+ try {
+ String propertyName = x.getPropertyName();
+ String propValue = null;
+ try {
+ SelectionProperty selProp = oracle.getSelectionProperty(logger,
+ propertyName);
+ propValue = selProp.getCurrentValue();
+ } catch (BadPropertyValueException e) {
+ ConfigurationProperty confProp = oracle.getConfigurationProperty(propertyName);
+ propValue = confProp.getValues().get(0);
+ }
+
+ /*
+ * If the deferred binding property's value is in the list of values in
+ * the @if rule, move the rules into the @if's context.
+ */
+ if (Arrays.asList(x.getPropertyValues()).contains(propValue)
+ ^ x.isNegated()) {
+ for (CssNode n : x.getNodes()) {
+ ctx.insertBefore(n);
+ }
+ } else {
+ // Otherwise, move the else block into the if statement's position
+ for (CssNode n : x.getElseNodes()) {
+ ctx.insertBefore(n);
+ }
+ }
+
+ // Always delete @if rules that we can statically evaluate
+ ctx.removeMe();
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.ERROR, "Unable to evaluate @if block", e);
+ throw new CssCompilerException("Unable to parse CSS", e);
+ }
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/resources/css/MergeIdenticalSelectorsVisitor.java b/user/src/com/google/gwt/resources/css/MergeIdenticalSelectorsVisitor.java
new file mode 100644
index 0000000..08a03ed
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/MergeIdenticalSelectorsVisitor.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssIf;
+import com.google.gwt.resources.css.ast.CssMediaRule;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+import com.google.gwt.resources.css.ast.CssNode;
+import com.google.gwt.resources.css.ast.CssRule;
+import com.google.gwt.resources.css.ast.CssSelector;
+import com.google.gwt.resources.rg.CssResourceGenerator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Merges rules that have matching selectors.
+ */
+public class MergeIdenticalSelectorsVisitor extends CssModVisitor {
+ private final Map<String, CssRule> canonicalRules = new HashMap<String, CssRule>();
+ private final List<CssRule> rulesInOrder = new ArrayList<CssRule>();
+
+ @Override
+ public boolean visit(CssIf x, Context ctx) {
+ visitInNewContext(x.getNodes());
+ visitInNewContext(x.getElseNodes());
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssMediaRule x, Context ctx) {
+ visitInNewContext(x.getNodes());
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssRule x, Context ctx) {
+ // Assumed to run immediately after SplitRulesVisitor
+ assert x.getSelectors().size() == 1;
+ CssSelector sel = x.getSelectors().get(0);
+
+ if (canonicalRules.containsKey(sel.getSelector())) {
+ CssRule canonical = canonicalRules.get(sel.getSelector());
+
+ // Check everything between the canonical rule and this rule for common
+ // properties. If there are common properties, it would be unsafe to
+ // promote the rule.
+ boolean hasCommon = false;
+ int index = rulesInOrder.indexOf(canonical) + 1;
+ assert index != 0;
+
+ for (Iterator<CssRule> i = rulesInOrder.listIterator(index); i.hasNext()
+ && !hasCommon;) {
+ hasCommon = CssResourceGenerator.haveCommonProperties(i.next(), x);
+ }
+
+ if (!hasCommon) {
+ // It's safe to promote the rule
+ canonical.getProperties().addAll(x.getProperties());
+ ctx.removeMe();
+ return false;
+ }
+ }
+
+ canonicalRules.put(sel.getSelector(), x);
+ rulesInOrder.add(x);
+ return false;
+ }
+
+ private void visitInNewContext(List<CssNode> nodes) {
+ MergeIdenticalSelectorsVisitor v = new MergeIdenticalSelectorsVisitor();
+ v.acceptWithInsertRemove(nodes);
+ rulesInOrder.addAll(v.rulesInOrder);
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/MergeRulesByContentVisitor.java b/user/src/com/google/gwt/resources/css/MergeRulesByContentVisitor.java
new file mode 100644
index 0000000..ea3e276
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/MergeRulesByContentVisitor.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssIf;
+import com.google.gwt.resources.css.ast.CssMediaRule;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+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.rg.CssResourceGenerator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Merges rules that have identical content.
+ */
+public class MergeRulesByContentVisitor extends CssModVisitor {
+ private Map<String, CssRule> rulesByContents = new HashMap<String, CssRule>();
+ private final List<CssRule> rulesInOrder = new ArrayList<CssRule>();
+
+ @Override
+ public boolean visit(CssIf x, Context ctx) {
+ visitInNewContext(x.getNodes());
+ visitInNewContext(x.getElseNodes());
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssMediaRule x, Context ctx) {
+ visitInNewContext(x.getNodes());
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssRule x, Context ctx) {
+ StringBuilder b = new StringBuilder();
+ for (CssProperty p : x.getProperties()) {
+ b.append(p.getName()).append(":").append(p.getValues().getExpression());
+ }
+
+ String content = b.toString();
+ CssRule canonical = rulesByContents.get(content);
+
+ // Check everything between the canonical rule and this rule for common
+ // properties. If there are common properties, it would be unsafe to
+ // promote the rule.
+ if (canonical != null) {
+ boolean hasCommon = false;
+ int index = rulesInOrder.indexOf(canonical) + 1;
+ assert index != 0;
+
+ for (Iterator<CssRule> i = rulesInOrder.listIterator(index); i.hasNext()
+ && !hasCommon;) {
+ hasCommon = CssResourceGenerator.haveCommonProperties(i.next(), x);
+ }
+
+ if (!hasCommon) {
+ canonical.getSelectors().addAll(x.getSelectors());
+ ctx.removeMe();
+ return false;
+ }
+ }
+
+ rulesByContents.put(content, x);
+ rulesInOrder.add(x);
+ return false;
+ }
+
+ private void visitInNewContext(List<CssNode> nodes) {
+ MergeRulesByContentVisitor v = new MergeRulesByContentVisitor();
+ v.acceptWithInsertRemove(nodes);
+ rulesInOrder.addAll(v.rulesInOrder);
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/RequirementsCollector.java b/user/src/com/google/gwt/resources/css/RequirementsCollector.java
new file mode 100644
index 0000000..125e348
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/RequirementsCollector.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssIf;
+import com.google.gwt.resources.css.ast.CssVisitor;
+import com.google.gwt.resources.ext.ClientBundleRequirements;
+
+/**
+ * Analyzes a stylesheet to update the ClientBundleRequirements interface.
+ */
+public class RequirementsCollector extends CssVisitor {
+ private final TreeLogger logger;
+ private final ClientBundleRequirements requirements;
+
+ public RequirementsCollector(TreeLogger logger,
+ ClientBundleRequirements requirements) {
+ this.logger = logger.branch(TreeLogger.DEBUG,
+ "Scanning CSS for requirements");
+ this.requirements = requirements;
+ }
+
+ @Override
+ public void endVisit(CssIf x, Context ctx) {
+ String propertyName = x.getPropertyName();
+ if (propertyName != null) {
+ try {
+ requirements.addPermutationAxis(propertyName);
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.ERROR, "Unknown deferred-binding property "
+ + propertyName, e);
+ throw new CssCompilerException("Unknown deferred-binding property", e);
+ }
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/resources/css/RtlVisitor.java b/user/src/com/google/gwt/resources/css/RtlVisitor.java
new file mode 100644
index 0000000..3994231
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/RtlVisitor.java
@@ -0,0 +1,290 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+import com.google.gwt.resources.css.ast.CssNoFlip;
+import com.google.gwt.resources.css.ast.CssProperty;
+import com.google.gwt.resources.css.ast.CssRule;
+import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
+import com.google.gwt.resources.css.ast.CssProperty.NumberValue;
+import com.google.gwt.resources.css.ast.CssProperty.Value;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Applies RTL transforms to a stylesheet.
+ */
+public class RtlVisitor extends CssModVisitor {
+ /**
+ * Records if we're currently visiting a CssRule whose only selector is
+ * "body".
+ */
+ private boolean inBodyRule;
+
+ @Override
+ public void endVisit(CssProperty x, Context ctx) {
+ String name = x.getName();
+
+ if (name.equalsIgnoreCase("left")) {
+ x.setName("right");
+ } else if (name.equalsIgnoreCase("right")) {
+ x.setName("left");
+ } else if (name.endsWith("-left")) {
+ int len = name.length();
+ x.setName(name.substring(0, len - 4) + "right");
+ } else if (name.endsWith("-right")) {
+ int len = name.length();
+ x.setName(name.substring(0, len - 5) + "left");
+ } else if (name.contains("-right-")) {
+ x.setName(name.replace("-right-", "-left-"));
+ } else if (name.contains("-left-")) {
+ x.setName(name.replace("-left-", "-right-"));
+ } else {
+ List<Value> values = new ArrayList<Value>(x.getValues().getValues());
+ invokePropertyHandler(x.getName(), values);
+ x.setValue(new CssProperty.ListValue(values));
+ }
+ }
+
+ @Override
+ public boolean visit(CssNoFlip x, Context ctx) {
+ return false;
+ }
+
+ @Override
+ public boolean visit(CssRule x, Context ctx) {
+ inBodyRule = x.getSelectors().size() == 1
+ && x.getSelectors().get(0).getSelector().equals("body");
+ return true;
+ }
+
+ void propertyHandlerBackground(List<Value> values) {
+ /*
+ * The first numeric value will be treated as the left position only if we
+ * havn't seen any value that could potentially be the left value.
+ */
+ boolean seenLeft = false;
+
+ for (ListIterator<Value> it = values.listIterator(); it.hasNext();) {
+ Value v = it.next();
+ Value maybeFlipped = flipLeftRightIdentValue(v);
+ NumberValue nv = v.isNumberValue();
+ if (v != maybeFlipped) {
+ it.set(maybeFlipped);
+ seenLeft = true;
+
+ } else if (isIdent(v, "center")) {
+ seenLeft = true;
+
+ } else if (!seenLeft && (nv != null)) {
+ seenLeft = true;
+ if ("%".equals(nv.getUnits())) {
+ float position = 100f - nv.getValue();
+ it.set(new NumberValue(position, "%"));
+ break;
+ }
+ }
+ }
+ }
+
+ void propertyHandlerBackgroundPosition(List<Value> values) {
+ propertyHandlerBackground(values);
+ }
+
+ Value propertyHandlerBackgroundPositionX(Value v) {
+ ArrayList<Value> list = new ArrayList<Value>(1);
+ list.add(v);
+ propertyHandlerBackground(list);
+ return list.get(0);
+ }
+
+ /**
+ * Note there should be no propertyHandlerBorder(). The CSS spec states that
+ * the border property must set all values at once.
+ */
+ void propertyHandlerBorderColor(List<Value> values) {
+ swapFour(values);
+ }
+
+ void propertyHandlerBorderStyle(List<Value> values) {
+ swapFour(values);
+ }
+
+ void propertyHandlerBorderWidth(List<Value> values) {
+ swapFour(values);
+ }
+
+ Value propertyHandlerClear(Value v) {
+ return propertyHandlerFloat(v);
+ }
+
+ Value propertyHandlerCursor(Value v) {
+ IdentValue identValue = v.isIdentValue();
+ if (identValue == null) {
+ return v;
+ }
+
+ String ident = identValue.getIdent().toLowerCase();
+ if (!ident.endsWith("-resize")) {
+ return v;
+ }
+
+ StringBuffer newIdent = new StringBuffer();
+
+ if (ident.length() == 9) {
+ if (ident.charAt(0) == 'n') {
+ newIdent.append('n');
+ ident = ident.substring(1);
+ } else if (ident.charAt(0) == 's') {
+ newIdent.append('s');
+ ident = ident.substring(1);
+ } else {
+ return v;
+ }
+ }
+
+ if (ident.length() == 8) {
+ if (ident.charAt(0) == 'e') {
+ newIdent.append("w-resize");
+ } else if (ident.charAt(0) == 'w') {
+ newIdent.append("e-resize");
+ } else {
+ return v;
+ }
+ return new IdentValue(newIdent.toString());
+ } else {
+ return v;
+ }
+ }
+
+ Value propertyHandlerDirection(Value v) {
+ if (inBodyRule) {
+ if (isIdent(v, "ltr")) {
+ return new IdentValue("rtl");
+ } else if (isIdent(v, "rtl")) {
+ return new IdentValue("ltr");
+ }
+ }
+ return v;
+ }
+
+ Value propertyHandlerFloat(Value v) {
+ return flipLeftRightIdentValue(v);
+ }
+
+ void propertyHandlerMargin(List<Value> values) {
+ swapFour(values);
+ }
+
+ void propertyHandlerPadding(List<Value> values) {
+ swapFour(values);
+ }
+
+ Value propertyHandlerPageBreakAfter(Value v) {
+ return flipLeftRightIdentValue(v);
+ }
+
+ Value propertyHandlerPageBreakBefore(Value v) {
+ return flipLeftRightIdentValue(v);
+ }
+
+ Value propertyHandlerTextAlign(Value v) {
+ return flipLeftRightIdentValue(v);
+ }
+
+ private Value flipLeftRightIdentValue(Value v) {
+ if (isIdent(v, "right")) {
+ return new IdentValue("left");
+
+ } else if (isIdent(v, "left")) {
+ return new IdentValue("right");
+ }
+ return v;
+ }
+
+ /**
+ * Reflectively invokes a propertyHandler method for the named property.
+ * Dashed names are transformed into camel-case names; only letters following
+ * a dash will be capitalized when looking for a method to prevent
+ * <code>fooBar<code> and <code>foo-bar</code> from colliding.
+ */
+ private void invokePropertyHandler(String name, List<Value> values) {
+ // See if we have a property-handler function
+ try {
+ String[] parts = name.toLowerCase().split("-");
+ StringBuffer methodName = new StringBuffer("propertyHandler");
+ for (String part : parts) {
+ methodName.append(Character.toUpperCase(part.charAt(0)));
+ methodName.append(part, 1, part.length());
+ }
+
+ try {
+ // Single-arg for simplicity
+ Method m = getClass().getDeclaredMethod(methodName.toString(),
+ Value.class);
+ assert Value.class.isAssignableFrom(m.getReturnType());
+ Value newValue = (Value) m.invoke(this, values.get(0));
+ values.set(0, newValue);
+ } catch (NoSuchMethodException e) {
+ // OK
+ }
+
+ try {
+ // Or the whole List for completeness
+ Method m = getClass().getDeclaredMethod(methodName.toString(),
+ List.class);
+ m.invoke(this, values);
+ } catch (NoSuchMethodException e) {
+ // OK
+ }
+
+ } catch (SecurityException e) {
+ throw new CssCompilerException(
+ "Unable to invoke property handler function for " + name, e);
+ } catch (IllegalArgumentException e) {
+ throw new CssCompilerException(
+ "Unable to invoke property handler function for " + name, e);
+ } catch (IllegalAccessException e) {
+ throw new CssCompilerException(
+ "Unable to invoke property handler function for " + name, e);
+ } catch (InvocationTargetException e) {
+ throw new CssCompilerException(
+ "Unable to invoke property handler function for " + name, e);
+ }
+ }
+
+ private boolean isIdent(Value value, String query) {
+ IdentValue v = value.isIdentValue();
+ return v != null && v.getIdent().equalsIgnoreCase(query);
+ }
+
+ /**
+ * Swaps the second and fourth values in a list of four values.
+ */
+ private void swapFour(List<Value> values) {
+ if (values.size() == 4) {
+ Collections.swap(values, 1, 3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/SplitRulesVisitor.java b/user/src/com/google/gwt/resources/css/SplitRulesVisitor.java
new file mode 100644
index 0000000..646bed7
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/SplitRulesVisitor.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+import com.google.gwt.resources.css.ast.CssNodeCloner;
+import com.google.gwt.resources.css.ast.CssProperty;
+import com.google.gwt.resources.css.ast.CssRule;
+import com.google.gwt.resources.css.ast.CssSelector;
+
+/**
+ * Splits rules with compound selectors into multiple rules.
+ */
+public class SplitRulesVisitor extends CssModVisitor {
+ @Override
+ public void endVisit(CssRule x, Context ctx) {
+ if (x.getSelectors().size() == 1) {
+ return;
+ }
+
+ for (CssSelector sel : x.getSelectors()) {
+ CssRule newRule = new CssRule();
+ newRule.getSelectors().add(sel);
+ newRule.getProperties().addAll(
+ CssNodeCloner.clone(CssProperty.class, x.getProperties()));
+ ctx.insertBefore(newRule);
+ }
+ ctx.removeMe();
+ return;
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/Spriter.java b/user/src/com/google/gwt/resources/css/Spriter.java
new file mode 100644
index 0000000..6e48d37
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/Spriter.java
@@ -0,0 +1,150 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssModVisitor;
+import com.google.gwt.resources.css.ast.CssProperty;
+import com.google.gwt.resources.css.ast.CssRule;
+import com.google.gwt.resources.css.ast.CssSprite;
+import com.google.gwt.resources.css.ast.CssProperty.ExpressionValue;
+import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
+import com.google.gwt.resources.ext.ResourceContext;
+
+import java.util.List;
+
+/**
+ * Replaces CssSprite nodes with CssRule nodes that will display the sprited
+ * image. The real trick with spriting the images is to reuse the ImageResource
+ * processing framework by requiring the sprite to be defined in terms of an
+ * ImageResource.
+ */
+public class Spriter extends CssModVisitor {
+ private final ResourceContext context;
+ private final TreeLogger logger;
+
+ public Spriter(TreeLogger logger, ResourceContext context) {
+ this.logger = logger.branch(TreeLogger.DEBUG,
+ "Creating image sprite classes");
+ this.context = context;
+ }
+
+ @Override
+ public void endVisit(CssSprite x, Context ctx) {
+ JClassType bundleType = context.getClientBundleType();
+ String functionName = x.getResourceFunction();
+
+ if (functionName == null) {
+ logger.log(TreeLogger.ERROR, "The @sprite rule " + x.getSelectors()
+ + " must specify the " + CssSprite.IMAGE_PROPERTY_NAME + " property");
+ throw new CssCompilerException("No image property specified");
+ }
+
+ // Find the image accessor method
+ JMethod imageMethod = null;
+ JMethod[] allMethods = bundleType.getOverridableMethods();
+ for (int i = 0; imageMethod == null && i < allMethods.length; i++) {
+ JMethod candidate = allMethods[i];
+ // If the function name matches and takes no parameters
+ if (candidate.getName().equals(functionName)
+ && candidate.getParameters().length == 0) {
+ // We have a match
+ imageMethod = candidate;
+ }
+ }
+
+ // Method unable to be located
+ if (imageMethod == null) {
+ logger.log(TreeLogger.ERROR, "Unable to find ImageResource method "
+ + functionName + " in " + bundleType.getQualifiedSourceName());
+ throw new CssCompilerException("Cannot find image function");
+ }
+
+ JClassType imageResourceType = context.getGeneratorContext().getTypeOracle().findType(
+ ImageResource.class.getName());
+ assert imageResourceType != null;
+
+ if (!imageResourceType.isAssignableFrom(imageMethod.getReturnType().isClassOrInterface())) {
+ logger.log(TreeLogger.ERROR, "The return type of " + functionName
+ + " is not assignable to " + imageResourceType.getSimpleSourceName());
+ throw new CssCompilerException("Incorrect return type for "
+ + CssSprite.IMAGE_PROPERTY_NAME + " method");
+ }
+
+ ImageOptions options = imageMethod.getAnnotation(ImageOptions.class);
+ RepeatStyle repeatStyle;
+ if (options != null) {
+ repeatStyle = options.repeatStyle();
+ } else {
+ repeatStyle = RepeatStyle.None;
+ }
+
+ String instance = "(" + context.getImplementationSimpleSourceName()
+ + ".this." + functionName + "())";
+
+ CssRule replacement = new CssRule();
+ replacement.getSelectors().addAll(x.getSelectors());
+ List<CssProperty> properties = replacement.getProperties();
+
+ if (repeatStyle == RepeatStyle.None
+ || repeatStyle == RepeatStyle.Horizontal) {
+ properties.add(new CssProperty("height", new ExpressionValue(instance
+ + ".getHeight() + \"px\""), false));
+ }
+
+ if (repeatStyle == RepeatStyle.None || repeatStyle == RepeatStyle.Vertical) {
+ properties.add(new CssProperty("width", new ExpressionValue(instance
+ + ".getWidth() + \"px\""), false));
+ }
+ properties.add(new CssProperty("overflow", new IdentValue("hidden"), false));
+
+ String repeatText;
+ switch (repeatStyle) {
+ case None:
+ repeatText = " no-repeat";
+ break;
+ case Horizontal:
+ repeatText = " repeat-x";
+ break;
+ case Vertical:
+ repeatText = " repeat-y";
+ break;
+ case Both:
+ repeatText = " repeat";
+ break;
+ default:
+ throw new RuntimeException("Unknown repeatStyle " + repeatStyle);
+ }
+
+ String backgroundExpression = "\"url(\\\"\" + " + instance
+ + ".getURL() + \"\\\") -\" + " + instance + ".getLeft() + \"px -\" + "
+ + instance + ".getTop() + \"px " + repeatText + "\"";
+ properties.add(new CssProperty("background", new ExpressionValue(
+ backgroundExpression), false));
+
+ // Retain any user-specified properties
+ properties.addAll(x.getProperties());
+
+ ctx.replaceMe(replacement);
+ }
+}
diff --git a/user/src/com/google/gwt/resources/css/SubstitutionCollector.java b/user/src/com/google/gwt/resources/css/SubstitutionCollector.java
new file mode 100644
index 0000000..d6cf2a7
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/SubstitutionCollector.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+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.CssUrl;
+import com.google.gwt.resources.css.ast.CssVisitor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Collects all user-defined constant nodes in the stylesheet.
+ */
+public class SubstitutionCollector extends CssVisitor {
+ private final Map<String, CssDef> substitutions = new HashMap<String, CssDef>();
+
+ @Override
+ public void endVisit(CssDef x, Context ctx) {
+ substitutions.put(x.getKey(), x);
+ }
+
+ @Override
+ public void endVisit(CssEval x, Context ctx) {
+ substitutions.put(x.getKey(), x);
+ }
+
+ @Override
+ public void endVisit(CssUrl x, Context ctx) {
+ substitutions.put(x.getKey(), x);
+ }
+
+ public Map<String, CssDef> getSubstitutions() {
+ return substitutions;
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java b/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java
new file mode 100644
index 0000000..9cbbcc4
--- /dev/null
+++ b/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.resources.client.DataResource;
+import com.google.gwt.resources.css.ast.Context;
+import com.google.gwt.resources.css.ast.CssCompilerException;
+import com.google.gwt.resources.css.ast.CssDef;
+import com.google.gwt.resources.css.ast.CssProperty;
+import com.google.gwt.resources.css.ast.CssUrl;
+import com.google.gwt.resources.css.ast.CssVisitor;
+import com.google.gwt.resources.css.ast.CssProperty.ExpressionValue;
+import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
+import com.google.gwt.resources.css.ast.CssProperty.ListValue;
+import com.google.gwt.resources.css.ast.CssProperty.Value;
+import com.google.gwt.resources.ext.ResourceContext;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+/**
+ * Substitute symbolic replacements into string values.
+ */
+public class SubstitutionReplacer extends CssVisitor {
+ private final ResourceContext context;
+ private final TreeLogger logger;
+ private final Map<String, CssDef> substitutions;
+
+ public SubstitutionReplacer(TreeLogger logger, ResourceContext context,
+ Map<String, CssDef> substitutions) {
+ this.context = context;
+ this.logger = logger;
+ this.substitutions = substitutions;
+ }
+
+ @Override
+ public void endVisit(CssProperty x, Context ctx) {
+ if (x.getValues() == null) {
+ // Nothing to do
+ return;
+ }
+
+ List<Value> values = new ArrayList<Value>(x.getValues().getValues());
+
+ for (ListIterator<Value> i = values.listIterator(); i.hasNext();) {
+ IdentValue v = i.next().isIdentValue();
+
+ if (v == null) {
+ // Don't try to substitute into anything other than idents
+ continue;
+ }
+
+ String value = v.getIdent();
+ CssDef def = substitutions.get(value);
+
+ if (def == null) {
+ continue;
+ } else if (def instanceof CssUrl) {
+ assert def.getValues().size() == 1;
+ assert def.getValues().get(0).isIdentValue() != null;
+ String functionName = def.getValues().get(0).isIdentValue().getIdent();
+
+ // Find the method
+ JMethod methods[] = context.getClientBundleType().getOverridableMethods();
+ boolean foundMethod = false;
+ if (methods != null) {
+ for (JMethod method : methods) {
+ if (method.getName().equals(functionName)) {
+ foundMethod = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundMethod) {
+ logger.log(TreeLogger.ERROR, "Unable to find DataResource method "
+ + functionName + " in "
+ + context.getClientBundleType().getQualifiedSourceName());
+ throw new CssCompilerException("Cannot find data function");
+ }
+
+ String instance = "((" + DataResource.class.getName() + ")("
+ + context.getImplementationSimpleSourceName() + ".this."
+ + functionName + "()))";
+
+ StringBuilder expression = new StringBuilder();
+ expression.append("\"url('\" + ");
+ expression.append(instance).append(".getUrl()");
+ expression.append(" + \"')\"");
+ i.set(new ExpressionValue(expression.toString()));
+
+ } else {
+ i.remove();
+ for (Value defValue : def.getValues()) {
+ i.add(defValue);
+ }
+ }
+ }
+
+ x.setValue(new ListValue(values));
+ }
+}
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index adbf29c..85846d4 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -19,7 +19,6 @@
import com.google.gwt.core.ext.ConfigurationProperty;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.PropertyOracle;
-import com.google.gwt.core.ext.SelectionProperty;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -31,43 +30,39 @@
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.dom.client.StyleInjector;
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;
import com.google.gwt.resources.client.CssResource.ClassName;
import com.google.gwt.resources.client.CssResource.Import;
import com.google.gwt.resources.client.CssResource.ImportedWithPrefix;
import com.google.gwt.resources.client.CssResource.NotStrict;
import com.google.gwt.resources.client.CssResource.Shared;
import com.google.gwt.resources.client.CssResource.Strict;
-import com.google.gwt.resources.client.ImageResource.ImageOptions;
-import com.google.gwt.resources.client.ImageResource.RepeatStyle;
+import com.google.gwt.resources.css.ClassRenamer;
import com.google.gwt.resources.css.CssGenerationVisitor;
+import com.google.gwt.resources.css.DefsCollector;
+import com.google.gwt.resources.css.ExternalClassesCollector;
import com.google.gwt.resources.css.GenerateCssAst;
+import com.google.gwt.resources.css.IfEvaluator;
+import com.google.gwt.resources.css.MergeIdenticalSelectorsVisitor;
+import com.google.gwt.resources.css.MergeRulesByContentVisitor;
+import com.google.gwt.resources.css.RequirementsCollector;
+import com.google.gwt.resources.css.RtlVisitor;
+import com.google.gwt.resources.css.SplitRulesVisitor;
+import com.google.gwt.resources.css.Spriter;
+import com.google.gwt.resources.css.SubstitutionCollector;
+import com.google.gwt.resources.css.SubstitutionReplacer;
import com.google.gwt.resources.css.ast.CollapsedNode;
-import com.google.gwt.resources.css.ast.Context;
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;
-import com.google.gwt.resources.css.ast.CssNoFlip;
import com.google.gwt.resources.css.ast.CssNode;
-import com.google.gwt.resources.css.ast.CssNodeCloner;
import com.google.gwt.resources.css.ast.CssProperty;
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.CssStylesheet;
-import com.google.gwt.resources.css.ast.CssUrl;
-import com.google.gwt.resources.css.ast.CssVisitor;
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.ExpressionValue;
-import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
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;
@@ -79,341 +74,23 @@
import com.google.gwt.user.rebind.StringSourceWriter;
import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.net.URL;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.regex.Matcher;
import java.util.zip.Adler32;
/**
* Provides implementations of CSSResources.
*/
public final class CssResourceGenerator extends AbstractResourceGenerator {
- static class ClassRenamer extends CssVisitor {
-
- /**
- * A tag to indicate that an externally-defined CSS class has no JMethod
- * that is used to access it.
- */
- private static final Replacement UNREFERENCED_EXTERNAL = new Replacement(
- null, null);
-
- /*
- * TODO: Replace with Pair<A, B>.
- */
- private static class Replacement {
-
- private JMethod method;
- private String obfuscatedClassName;
-
- public Replacement(JMethod method, String obfuscatedClassName) {
- this.method = method;
- this.obfuscatedClassName = obfuscatedClassName;
- }
-
- public JMethod getMethod() {
- return method;
- }
-
- public String getObfuscatedClassName() {
- return obfuscatedClassName;
- }
-
- /**
- * For debugging use only.
- */
- public String toString() {
- if (this == UNREFERENCED_EXTERNAL) {
- return "Unreferenced external class name";
- } else {
- return method.getName() + "=" + obfuscatedClassName;
- }
- }
- }
-
- /**
- * Records replacements that have actually been performed.
- */
- private final Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod, String>();
- 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 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.strict = strict;
-
- potentialReplacements = computeReplacements(classReplacementsWithPrefix,
- externalClasses);
-
- // Require a definition for all classes in the default namespace
- assert classReplacementsWithPrefix.containsKey("");
- missingClasses = new HashSet<JMethod>(
- classReplacementsWithPrefix.get("").keySet());
- }
-
- @Override
- public void endVisit(CssDef x, Context ctx) {
- cssDefs.add(x.getKey());
- }
-
- @Override
- public void endVisit(CssSelector x, Context ctx) {
-
- String sel = x.getSelector();
- int originalLength = sel.length();
-
- Matcher ma = CssSelector.CLASS_SELECTOR_PATTERN.matcher(sel);
- StringBuilder sb = new StringBuilder(originalLength);
- int start = 0;
-
- while (ma.find()) {
- String sourceClassName = ma.group(1);
-
- Replacement entry = potentialReplacements.get(sourceClassName);
-
- if (entry == null) {
- unknownClasses.add(sourceClassName);
- continue;
-
- } else if (entry == UNREFERENCED_EXTERNAL) {
- // An @external without an accessor method. This is OK.
- continue;
- }
-
- JMethod method = entry.getMethod();
- String obfuscatedClassName = entry.getObfuscatedClassName();
-
- // Consume the interstitial portion of the original selector
- sb.append(sel.subSequence(start, ma.start(1)));
- sb.append(obfuscatedClassName);
- start = ma.end(1);
-
- actualReplacements.put(method, obfuscatedClassName);
- missingClasses.remove(method);
- }
-
- if (start != 0) {
- // Consume the remainder and update the selector
- sb.append(sel.subSequence(start, originalLength));
- x.setSelector(sb.toString());
- }
- }
-
- @Override
- public void endVisit(CssStylesheet x, Context ctx) {
- boolean stop = false;
-
- // Skip names corresponding to @def entries. They too can be declared as
- // String accessors.
- List<JMethod> toRemove = new ArrayList<JMethod>();
- for (JMethod method : missingClasses) {
- if (cssDefs.contains(method.getName())) {
- toRemove.add(method);
- }
- }
- for (JMethod method : toRemove) {
- missingClasses.remove(method);
- }
-
- if (!missingClasses.isEmpty()) {
- stop = true;
- TreeLogger errorLogger = logger.branch(TreeLogger.INFO,
- "The following obfuscated style classes were missing from "
- + "the source CSS file:");
- for (JMethod m : missingClasses) {
- String name = m.getName();
- ClassName className = m.getAnnotation(ClassName.class);
- if (className != null) {
- name = className.value();
- }
- errorLogger.log(TreeLogger.ERROR, name + ": Fix by adding ." + name
- + "{}");
- }
- }
-
- if (strict && !unknownClasses.isEmpty()) {
- stop = true;
- TreeLogger errorLogger = logger.branch(TreeLogger.ERROR,
- "The following unobfuscated classes were present in a strict CssResource:");
- for (String s : unknownClasses) {
- errorLogger.log(TreeLogger.ERROR, s);
- }
- errorLogger.log(TreeLogger.INFO, "Fix by adding String accessor "
- + "method(s) to the CssResource interface for obfuscated classes, "
- + "or using an @external declaration for unobfuscated classes.");
- }
-
- if (stop) {
- throw new CssCompilerException("Missing a CSS replacement");
- }
- }
-
- /**
- * Reports the replacements that were actually performed by this visitor.
- */
- public Map<JMethod, String> getReplacements() {
- return actualReplacements;
- }
-
- /**
- * Flatten class name lookups to speed selector rewriting.
- *
- * @param classReplacementsWithPrefix 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.
- * @return A flattened version of the classReplacementWithPrefix map, where
- * the keys are the source class name (with prefix included), and
- * values have the obfuscated class name and associated JMethod.
- */
- private Map<String, Replacement> computeReplacements(
- Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
- Set<String> externalClasses) {
-
- Map<String, Replacement> toReturn = new HashMap<String, Replacement>();
-
- for (String externalClass : externalClasses) {
- toReturn.put(externalClass, UNREFERENCED_EXTERNAL);
- }
-
- for (Map.Entry<String, Map<JMethod, String>> outerEntry : classReplacementsWithPrefix.entrySet()) {
- String prefix = outerEntry.getKey();
-
- for (Map.Entry<JMethod, String> entry : outerEntry.getValue().entrySet()) {
- JMethod method = entry.getKey();
- String sourceClassName = method.getName();
- String obfuscatedClassName = entry.getValue();
-
- ClassName className = method.getAnnotation(ClassName.class);
- if (className != null) {
- sourceClassName = className.value();
- }
-
- sourceClassName = prefix + sourceClassName;
-
- if (externalClasses.contains(sourceClassName)) {
- /*
- * It simplifies the sanity-checking logic to treat external classes
- * as though they were simply obfuscated to exactly the value the
- * user wants.
- */
- obfuscatedClassName = sourceClassName;
- }
-
- toReturn.put(sourceClassName, new Replacement(method,
- obfuscatedClassName));
- }
- }
- return Collections.unmodifiableMap(toReturn);
- }
- }
-
- static class DefsCollector extends CssVisitor {
- private final Set<String> defs = new HashSet<String>();
-
- @Override
- public void endVisit(CssDef x, Context ctx) {
- defs.add(x.getKey());
- }
- }
-
- /**
- * 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;
- }
- }
-
- /**
- * Statically evaluates {@literal @if} rules.
- */
- static class IfEvaluator extends CssModVisitor {
- private final TreeLogger logger;
- private final PropertyOracle oracle;
-
- public IfEvaluator(TreeLogger logger, PropertyOracle oracle) {
- this.logger = logger.branch(TreeLogger.DEBUG,
- "Replacing property-based @if blocks");
- this.oracle = oracle;
- }
-
- @Override
- public void endVisit(CssIf x, Context ctx) {
- if (x.getExpression() != null) {
- // This gets taken care of by the runtime substitution visitor
- } else {
- try {
- String propertyName = x.getPropertyName();
- String propValue = null;
- try {
- SelectionProperty selProp = oracle.getSelectionProperty(logger,
- propertyName);
- propValue = selProp.getCurrentValue();
- } catch (BadPropertyValueException e) {
- ConfigurationProperty confProp = oracle.getConfigurationProperty(propertyName);
- propValue = confProp.getValues().get(0);
- }
-
- /*
- * If the deferred binding property's value is in the list of values
- * in the @if rule, move the rules into the @if's context.
- */
- if (Arrays.asList(x.getPropertyValues()).contains(propValue)
- ^ x.isNegated()) {
- for (CssNode n : x.getNodes()) {
- ctx.insertBefore(n);
- }
- } else {
- // Otherwise, move the else block into the if statement's position
- for (CssNode n : x.getElseNodes()) {
- ctx.insertBefore(n);
- }
- }
-
- // Always delete @if rules that we can statically evaluate
- ctx.removeMe();
- } catch (BadPropertyValueException e) {
- logger.log(TreeLogger.ERROR, "Unable to evaluate @if block", e);
- throw new CssCompilerException("Unable to parse CSS", e);
- }
- }
- }
- }
@SuppressWarnings("serial")
static class JClassOrderComparator implements Comparator<JClassType>,
@@ -424,654 +101,6 @@
}
/**
- * Merges rules that have matching selectors.
- */
- static class MergeIdenticalSelectorsVisitor extends CssModVisitor {
- private final Map<String, CssRule> canonicalRules = new HashMap<String, CssRule>();
- private final List<CssRule> rulesInOrder = new ArrayList<CssRule>();
-
- @Override
- public boolean visit(CssIf x, Context ctx) {
- visitInNewContext(x.getNodes());
- visitInNewContext(x.getElseNodes());
- return false;
- }
-
- @Override
- public boolean visit(CssMediaRule x, Context ctx) {
- visitInNewContext(x.getNodes());
- return false;
- }
-
- @Override
- public boolean visit(CssRule x, Context ctx) {
- // Assumed to run immediately after SplitRulesVisitor
- assert x.getSelectors().size() == 1;
- CssSelector sel = x.getSelectors().get(0);
-
- if (canonicalRules.containsKey(sel.getSelector())) {
- CssRule canonical = canonicalRules.get(sel.getSelector());
-
- // Check everything between the canonical rule and this rule for common
- // properties. If there are common properties, it would be unsafe to
- // promote the rule.
- boolean hasCommon = false;
- int index = rulesInOrder.indexOf(canonical) + 1;
- assert index != 0;
-
- for (Iterator<CssRule> i = rulesInOrder.listIterator(index); i.hasNext()
- && !hasCommon;) {
- hasCommon = haveCommonProperties(i.next(), x);
- }
-
- if (!hasCommon) {
- // It's safe to promote the rule
- canonical.getProperties().addAll(x.getProperties());
- ctx.removeMe();
- return false;
- }
- }
-
- canonicalRules.put(sel.getSelector(), x);
- rulesInOrder.add(x);
- return false;
- }
-
- private void visitInNewContext(List<CssNode> nodes) {
- MergeIdenticalSelectorsVisitor v = new MergeIdenticalSelectorsVisitor();
- v.acceptWithInsertRemove(nodes);
- rulesInOrder.addAll(v.rulesInOrder);
- }
- }
-
- /**
- * Merges rules that have identical content.
- */
- static class MergeRulesByContentVisitor extends CssModVisitor {
- private Map<String, CssRule> rulesByContents = new HashMap<String, CssRule>();
- private final List<CssRule> rulesInOrder = new ArrayList<CssRule>();
-
- @Override
- public boolean visit(CssIf x, Context ctx) {
- visitInNewContext(x.getNodes());
- visitInNewContext(x.getElseNodes());
- return false;
- }
-
- @Override
- public boolean visit(CssMediaRule x, Context ctx) {
- visitInNewContext(x.getNodes());
- return false;
- }
-
- @Override
- public boolean visit(CssRule x, Context ctx) {
- StringBuilder b = new StringBuilder();
- for (CssProperty p : x.getProperties()) {
- b.append(p.getName()).append(":").append(p.getValues().getExpression());
- }
-
- String content = b.toString();
- CssRule canonical = rulesByContents.get(content);
-
- // Check everything between the canonical rule and this rule for common
- // properties. If there are common properties, it would be unsafe to
- // promote the rule.
- if (canonical != null) {
- boolean hasCommon = false;
- int index = rulesInOrder.indexOf(canonical) + 1;
- assert index != 0;
-
- for (Iterator<CssRule> i = rulesInOrder.listIterator(index); i.hasNext()
- && !hasCommon;) {
- hasCommon = haveCommonProperties(i.next(), x);
- }
-
- if (!hasCommon) {
- canonical.getSelectors().addAll(x.getSelectors());
- ctx.removeMe();
- return false;
- }
- }
-
- rulesByContents.put(content, x);
- rulesInOrder.add(x);
- return false;
- }
-
- private void visitInNewContext(List<CssNode> nodes) {
- MergeRulesByContentVisitor v = new MergeRulesByContentVisitor();
- v.acceptWithInsertRemove(nodes);
- rulesInOrder.addAll(v.rulesInOrder);
- }
- }
-
- static class RequirementsCollector extends CssVisitor {
- private final TreeLogger logger;
- private final ClientBundleRequirements requirements;
-
- public RequirementsCollector(TreeLogger logger,
- ClientBundleRequirements requirements) {
- this.logger = logger.branch(TreeLogger.DEBUG,
- "Scanning CSS for requirements");
- this.requirements = requirements;
- }
-
- @Override
- public void endVisit(CssIf x, Context ctx) {
- String propertyName = x.getPropertyName();
- if (propertyName != null) {
- try {
- requirements.addPermutationAxis(propertyName);
- } catch (BadPropertyValueException e) {
- logger.log(TreeLogger.ERROR, "Unknown deferred-binding property "
- + propertyName, e);
- throw new CssCompilerException("Unknown deferred-binding property", e);
- }
- }
- }
- }
-
- static class RtlVisitor extends CssModVisitor {
- /**
- * Records if we're currently visiting a CssRule whose only selector is
- * "body".
- */
- private boolean inBodyRule;
-
- @Override
- public void endVisit(CssProperty x, Context ctx) {
- String name = x.getName();
-
- if (name.equalsIgnoreCase("left")) {
- x.setName("right");
- } else if (name.equalsIgnoreCase("right")) {
- x.setName("left");
- } else if (name.endsWith("-left")) {
- int len = name.length();
- x.setName(name.substring(0, len - 4) + "right");
- } else if (name.endsWith("-right")) {
- int len = name.length();
- x.setName(name.substring(0, len - 5) + "left");
- } else if (name.contains("-right-")) {
- x.setName(name.replace("-right-", "-left-"));
- } else if (name.contains("-left-")) {
- x.setName(name.replace("-left-", "-right-"));
- } else {
- List<Value> values = new ArrayList<Value>(x.getValues().getValues());
- invokePropertyHandler(x.getName(), values);
- x.setValue(new CssProperty.ListValue(values));
- }
- }
-
- @Override
- public boolean visit(CssNoFlip x, Context ctx) {
- return false;
- }
-
- @Override
- public boolean visit(CssRule x, Context ctx) {
- inBodyRule = x.getSelectors().size() == 1
- && x.getSelectors().get(0).getSelector().equals("body");
- return true;
- }
-
- void propertyHandlerBackground(List<Value> values) {
- /*
- * The first numeric value will be treated as the left position only if we
- * havn't seen any value that could potentially be the left value.
- */
- boolean seenLeft = false;
-
- for (ListIterator<Value> it = values.listIterator(); it.hasNext();) {
- Value v = it.next();
- Value maybeFlipped = flipLeftRightIdentValue(v);
- NumberValue nv = v.isNumberValue();
- if (v != maybeFlipped) {
- it.set(maybeFlipped);
- seenLeft = true;
-
- } else if (isIdent(v, "center")) {
- seenLeft = true;
-
- } else if (!seenLeft && (nv != null)) {
- seenLeft = true;
- if ("%".equals(nv.getUnits())) {
- float position = 100f - nv.getValue();
- it.set(new NumberValue(position, "%"));
- break;
- }
- }
- }
- }
-
- void propertyHandlerBackgroundPosition(List<Value> values) {
- propertyHandlerBackground(values);
- }
-
- Value propertyHandlerBackgroundPositionX(Value v) {
- ArrayList<Value> list = new ArrayList<Value>(1);
- list.add(v);
- propertyHandlerBackground(list);
- return list.get(0);
- }
-
- /**
- * Note there should be no propertyHandlerBorder(). The CSS spec states that
- * the border property must set all values at once.
- */
- void propertyHandlerBorderColor(List<Value> values) {
- swapFour(values);
- }
-
- void propertyHandlerBorderStyle(List<Value> values) {
- swapFour(values);
- }
-
- void propertyHandlerBorderWidth(List<Value> values) {
- swapFour(values);
- }
-
- Value propertyHandlerClear(Value v) {
- return propertyHandlerFloat(v);
- }
-
- Value propertyHandlerCursor(Value v) {
- IdentValue identValue = v.isIdentValue();
- if (identValue == null) {
- return v;
- }
-
- String ident = identValue.getIdent().toLowerCase();
- if (!ident.endsWith("-resize")) {
- return v;
- }
-
- StringBuffer newIdent = new StringBuffer();
-
- if (ident.length() == 9) {
- if (ident.charAt(0) == 'n') {
- newIdent.append('n');
- ident = ident.substring(1);
- } else if (ident.charAt(0) == 's') {
- newIdent.append('s');
- ident = ident.substring(1);
- } else {
- return v;
- }
- }
-
- if (ident.length() == 8) {
- if (ident.charAt(0) == 'e') {
- newIdent.append("w-resize");
- } else if (ident.charAt(0) == 'w') {
- newIdent.append("e-resize");
- } else {
- return v;
- }
- return new IdentValue(newIdent.toString());
- } else {
- return v;
- }
- }
-
- Value propertyHandlerDirection(Value v) {
- if (inBodyRule) {
- if (isIdent(v, "ltr")) {
- return new IdentValue("rtl");
- } else if (isIdent(v, "rtl")) {
- return new IdentValue("ltr");
- }
- }
- return v;
- }
-
- Value propertyHandlerFloat(Value v) {
- return flipLeftRightIdentValue(v);
- }
-
- void propertyHandlerMargin(List<Value> values) {
- swapFour(values);
- }
-
- void propertyHandlerPadding(List<Value> values) {
- swapFour(values);
- }
-
- Value propertyHandlerPageBreakAfter(Value v) {
- return flipLeftRightIdentValue(v);
- }
-
- Value propertyHandlerPageBreakBefore(Value v) {
- return flipLeftRightIdentValue(v);
- }
-
- Value propertyHandlerTextAlign(Value v) {
- return flipLeftRightIdentValue(v);
- }
-
- private Value flipLeftRightIdentValue(Value v) {
- if (isIdent(v, "right")) {
- return new IdentValue("left");
-
- } else if (isIdent(v, "left")) {
- return new IdentValue("right");
- }
- return v;
- }
-
- /**
- * Reflectively invokes a propertyHandler method for the named property.
- * Dashed names are transformed into camel-case names; only letters
- * following a dash will be capitalized when looking for a method to prevent
- * <code>fooBar<code> and <code>foo-bar</code> from colliding.
- */
- private void invokePropertyHandler(String name, List<Value> values) {
- // See if we have a property-handler function
- try {
- String[] parts = name.toLowerCase().split("-");
- StringBuffer methodName = new StringBuffer("propertyHandler");
- for (String part : parts) {
- methodName.append(Character.toUpperCase(part.charAt(0)));
- methodName.append(part, 1, part.length());
- }
-
- try {
- // Single-arg for simplicity
- Method m = getClass().getDeclaredMethod(methodName.toString(),
- Value.class);
- assert Value.class.isAssignableFrom(m.getReturnType());
- Value newValue = (Value) m.invoke(this, values.get(0));
- values.set(0, newValue);
- } catch (NoSuchMethodException e) {
- // OK
- }
-
- try {
- // Or the whole List for completeness
- Method m = getClass().getDeclaredMethod(methodName.toString(),
- List.class);
- m.invoke(this, values);
- } catch (NoSuchMethodException e) {
- // OK
- }
-
- } catch (SecurityException e) {
- throw new CssCompilerException(
- "Unable to invoke property handler function for " + name, e);
- } catch (IllegalArgumentException e) {
- throw new CssCompilerException(
- "Unable to invoke property handler function for " + name, e);
- } catch (IllegalAccessException e) {
- throw new CssCompilerException(
- "Unable to invoke property handler function for " + name, e);
- } catch (InvocationTargetException e) {
- throw new CssCompilerException(
- "Unable to invoke property handler function for " + name, e);
- }
- }
-
- private boolean isIdent(Value value, String query) {
- IdentValue v = value.isIdentValue();
- return v != null && v.getIdent().equalsIgnoreCase(query);
- }
-
- /**
- * Swaps the second and fourth values in a list of four values.
- */
- private void swapFour(List<Value> values) {
- if (values.size() == 4) {
- Collections.swap(values, 1, 3);
- }
- }
- }
-
- /**
- * Splits rules with compound selectors into multiple rules.
- */
- static class SplitRulesVisitor extends CssModVisitor {
- @Override
- public void endVisit(CssRule x, Context ctx) {
- if (x.getSelectors().size() == 1) {
- return;
- }
-
- for (CssSelector sel : x.getSelectors()) {
- CssRule newRule = new CssRule();
- newRule.getSelectors().add(sel);
- newRule.getProperties().addAll(
- CssNodeCloner.clone(CssProperty.class, x.getProperties()));
- ctx.insertBefore(newRule);
- }
- ctx.removeMe();
- return;
- }
- }
-
- /**
- * Replaces CssSprite nodes with CssRule nodes that will display the sprited
- * image. The real trick with spriting the images is to reuse the
- * ImageResource processing framework by requiring the sprite to be defined in
- * terms of an ImageResource.
- */
- static class Spriter extends CssModVisitor {
- private final ResourceContext context;
- private final TreeLogger logger;
-
- public Spriter(TreeLogger logger, ResourceContext context) {
- this.logger = logger.branch(TreeLogger.DEBUG,
- "Creating image sprite classes");
- this.context = context;
- }
-
- @Override
- public void endVisit(CssSprite x, Context ctx) {
- JClassType bundleType = context.getClientBundleType();
- String functionName = x.getResourceFunction();
-
- if (functionName == null) {
- logger.log(TreeLogger.ERROR, "The @sprite rule " + x.getSelectors()
- + " must specify the " + CssSprite.IMAGE_PROPERTY_NAME
- + " property");
- throw new CssCompilerException("No image property specified");
- }
-
- // Find the image accessor method
- JMethod imageMethod = null;
- JMethod[] allMethods = bundleType.getOverridableMethods();
- for (int i = 0; imageMethod == null && i < allMethods.length; i++) {
- JMethod candidate = allMethods[i];
- // If the function name matches and takes no parameters
- if (candidate.getName().equals(functionName)
- && candidate.getParameters().length == 0) {
- // We have a match
- imageMethod = candidate;
- }
- }
-
- // Method unable to be located
- if (imageMethod == null) {
- logger.log(TreeLogger.ERROR, "Unable to find ImageResource method "
- + functionName + " in " + bundleType.getQualifiedSourceName());
- throw new CssCompilerException("Cannot find image function");
- }
-
- JClassType imageResourceType = context.getGeneratorContext().getTypeOracle().findType(
- ImageResource.class.getName());
- assert imageResourceType != null;
-
- if (!imageResourceType.isAssignableFrom(imageMethod.getReturnType().isClassOrInterface())) {
- logger.log(TreeLogger.ERROR, "The return type of " + functionName
- + " is not assignable to "
- + imageResourceType.getSimpleSourceName());
- throw new CssCompilerException("Incorrect return type for "
- + CssSprite.IMAGE_PROPERTY_NAME + " method");
- }
-
- ImageOptions options = imageMethod.getAnnotation(ImageOptions.class);
- RepeatStyle repeatStyle;
- if (options != null) {
- repeatStyle = options.repeatStyle();
- } else {
- repeatStyle = RepeatStyle.None;
- }
-
- String instance = "(" + context.getImplementationSimpleSourceName()
- + ".this." + functionName + "())";
-
- CssRule replacement = new CssRule();
- replacement.getSelectors().addAll(x.getSelectors());
- List<CssProperty> properties = replacement.getProperties();
-
- if (repeatStyle == RepeatStyle.None
- || repeatStyle == RepeatStyle.Horizontal) {
- properties.add(new CssProperty("height", new ExpressionValue(instance
- + ".getHeight() + \"px\""), false));
- }
-
- if (repeatStyle == RepeatStyle.None
- || repeatStyle == RepeatStyle.Vertical) {
- properties.add(new CssProperty("width", new ExpressionValue(instance
- + ".getWidth() + \"px\""), false));
- }
- properties.add(new CssProperty("overflow", new IdentValue("hidden"),
- false));
-
- String repeatText;
- switch (repeatStyle) {
- case None:
- repeatText = " no-repeat";
- break;
- case Horizontal:
- repeatText = " repeat-x";
- break;
- case Vertical:
- repeatText = " repeat-y";
- break;
- case Both:
- repeatText = " repeat";
- break;
- default:
- throw new RuntimeException("Unknown repeatStyle " + repeatStyle);
- }
-
- String backgroundExpression = "\"url(\\\"\" + " + instance
- + ".getURL() + \"\\\") -\" + " + instance
- + ".getLeft() + \"px -\" + " + instance + ".getTop() + \"px "
- + repeatText + "\"";
- properties.add(new CssProperty("background", new ExpressionValue(
- backgroundExpression), false));
-
- // Retain any user-specified properties
- properties.addAll(x.getProperties());
-
- ctx.replaceMe(replacement);
- }
- }
-
- static class SubstitutionCollector extends CssVisitor {
- private final Map<String, CssDef> substitutions = new HashMap<String, CssDef>();
-
- @Override
- public void endVisit(CssDef x, Context ctx) {
- substitutions.put(x.getKey(), x);
- }
-
- @Override
- public void endVisit(CssEval x, Context ctx) {
- substitutions.put(x.getKey(), x);
- }
-
- @Override
- public void endVisit(CssUrl x, Context ctx) {
- substitutions.put(x.getKey(), x);
- }
- }
-
- /**
- * Substitute symbolic replacements into string values.
- */
- static class SubstitutionReplacer extends CssVisitor {
- private final ResourceContext context;
- private final TreeLogger logger;
- private final Map<String, CssDef> substitutions;
-
- public SubstitutionReplacer(TreeLogger logger, ResourceContext context,
- Map<String, CssDef> substitutions) {
- this.context = context;
- this.logger = logger;
- this.substitutions = substitutions;
- }
-
- @Override
- public void endVisit(CssProperty x, Context ctx) {
- if (x.getValues() == null) {
- // Nothing to do
- return;
- }
-
- List<Value> values = new ArrayList<Value>(x.getValues().getValues());
-
- for (ListIterator<Value> i = values.listIterator(); i.hasNext();) {
- IdentValue v = i.next().isIdentValue();
-
- if (v == null) {
- // Don't try to substitute into anything other than idents
- continue;
- }
-
- String value = v.getIdent();
- CssDef def = substitutions.get(value);
-
- if (def == null) {
- continue;
- } else if (def instanceof CssUrl) {
- assert def.getValues().size() == 1;
- assert def.getValues().get(0).isIdentValue() != null;
- String functionName = def.getValues().get(0).isIdentValue().getIdent();
-
- // Find the method
- JMethod methods[] = context.getClientBundleType().getOverridableMethods();
- boolean foundMethod = false;
- if (methods != null) {
- for (JMethod method : methods) {
- if (method.getName().equals(functionName)) {
- foundMethod = true;
- break;
- }
- }
- }
-
- if (!foundMethod) {
- logger.log(TreeLogger.ERROR, "Unable to find DataResource method "
- + functionName + " in "
- + context.getClientBundleType().getQualifiedSourceName());
- throw new CssCompilerException("Cannot find data function");
- }
-
- String instance = "((" + DataResource.class.getName() + ")("
- + context.getImplementationSimpleSourceName() + ".this."
- + functionName + "()))";
-
- StringBuilder expression = new StringBuilder();
- expression.append("\"url('\" + ");
- expression.append(instance).append(".getUrl()");
- expression.append(" + \"')\"");
- i.set(new ExpressionValue(expression.toString()));
-
- } else {
- i.remove();
- for (Value defValue : def.getValues()) {
- i.add(defValue);
- }
- }
- }
-
- x.setValue(new ListValue(values));
- }
- }
-
- /**
* A lookup table of base-32 chars we use to encode CSS idents. Because CSS
* class selectors may be case-insensitive, we don't have enough characters to
* use a base-64 encoding.
@@ -1096,13 +125,7 @@
private static final String KEY_CLASS_PREFIX = "prefix";
private static final String KEY_CLASS_COUNTER = "counter";
- public static void main(String[] args) {
- for (int i = 0; i < 1000; i++) {
- System.out.println(makeIdent(i));
- }
- }
-
- static boolean haveCommonProperties(CssRule a, CssRule b) {
+ public static boolean haveCommonProperties(CssRule a, CssRule b) {
if (a.getProperties().size() == 0 || b.getProperties().size() == 0) {
return false;
}
@@ -1149,6 +172,12 @@
return false;
}
+ public static void main(String[] args) {
+ for (int i = 0; i < 1000; i++) {
+ System.out.println(makeIdent(i));
+ }
+ }
+
/**
* Create a Java expression that evaluates to a string representation of the
* given node. Visible only for testing.
@@ -1377,6 +406,10 @@
}
}
+ // Methods defined by CssResource interface
+ writeEnsureInjected(sw);
+ writeGetName(method, sw);
+
sw.println("public String getText() {");
sw.indent();
boolean strict = isStrict(logger, context, method);
@@ -1388,12 +421,6 @@
sw.outdent();
sw.println("}");
- sw.println("public String getName() {");
- sw.indent();
- sw.println("return \"" + method.getName() + "\";");
- sw.outdent();
- sw.println("}");
-
/*
* getOverridableMethods is used to handle CssResources extending
* non-CssResource types. See the discussion in computeReplacementsForType.
@@ -1763,7 +790,7 @@
SubstitutionCollector collector = new SubstitutionCollector();
collector.accept(sheet);
- (new SubstitutionReplacer(logger, context, collector.substitutions)).accept(sheet);
+ (new SubstitutionReplacer(logger, context, collector.getSubstitutions())).accept(sheet);
// Evaluate @if statements based on deferred binding properties
(new IfEvaluator(logger,
@@ -1834,7 +861,7 @@
String name = toImplement.getName();
// TODO: Annotation for override
- CssDef def = collector.substitutions.get(name);
+ CssDef def = collector.getSubstitutions().get(name);
if (def == null) {
logger.log(TreeLogger.ERROR, "No @def rule for name " + name);
throw new UnableToCompleteException();
@@ -1884,6 +911,28 @@
sw.println("}");
}
+ private void writeEnsureInjected(SourceWriter sw) {
+ sw.println("private boolean injected;");
+ sw.println("public boolean ensureInjected() {");
+ sw.indent();
+ sw.println("if (!injected) {");
+ sw.indentln("injected = true;");
+ sw.indentln(StyleInjector.class.getName() + ".injectStylesheet(getText());");
+ sw.indentln("return true;");
+ sw.println("}");
+ sw.println("return false;");
+ sw.outdent();
+ sw.println("}");
+ }
+
+ private void writeGetName(JMethod method, SourceWriter sw) {
+ sw.println("public String getName() {");
+ sw.indent();
+ sw.println("return \"" + method.getName() + "\";");
+ sw.outdent();
+ sw.println("}");
+ }
+
/**
* Write all of the user-defined methods in the CssResource subtype.
*/
@@ -1895,22 +944,23 @@
// 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)) {
+ 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 (collector.defs.contains(name)
- && obfuscatedClassNames.containsKey(toImplement)) {
+ 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 (collector.defs.contains(toImplement.getName())
+ if (defs.contains(toImplement.getName())
&& toImplement.getParameters().length == 0) {
writeDefAssignment(logger, sw, toImplement, sheet);
} else if (toImplement.getReturnType().equals(stringType)
diff --git a/user/test/com/google/gwt/animation/client/AnimationTest.java b/user/test/com/google/gwt/animation/client/AnimationTest.java
index 1ed09cf..1249dfc 100644
--- a/user/test/com/google/gwt/animation/client/AnimationTest.java
+++ b/user/test/com/google/gwt/animation/client/AnimationTest.java
@@ -141,6 +141,7 @@
public void testCancelBeforeStarted() {
final TestAnimation anim = new TestAnimation();
double curTime = Duration.currentTimeMillis();
+ delayTestFinish(20 * DELAY_MULTIPLIER);
anim.run(10 * DELAY_MULTIPLIER, curTime + 10 * DELAY_MULTIPLIER);
// Check progress
@@ -168,9 +169,6 @@
finishTest();
}
}.schedule(15 * DELAY_MULTIPLIER);
-
- // Wait for test to finish
- delayTestFinish(20 * DELAY_MULTIPLIER);
}
/**
@@ -178,6 +176,7 @@
*/
public void testCancelWhenComplete() {
final TestAnimation anim = new TestAnimation();
+ delayTestFinish(25 * DELAY_MULTIPLIER);
anim.run(10 * DELAY_MULTIPLIER);
// Check progress
@@ -204,9 +203,6 @@
finishTest();
}
}.schedule(20 * DELAY_MULTIPLIER);
-
- // Wait for test to finish
- delayTestFinish(25 * DELAY_MULTIPLIER);
}
/**
@@ -214,6 +210,7 @@
*/
public void testCancelWhileRunning() {
final TestAnimation anim = new TestAnimation();
+ delayTestFinish(20 * DELAY_MULTIPLIER);
anim.run(50 * DELAY_MULTIPLIER);
// Check progress
@@ -239,9 +236,6 @@
finishTest();
}
}.schedule(15 * DELAY_MULTIPLIER);
-
- // Wait for test to finish
- delayTestFinish(20 * DELAY_MULTIPLIER);
}
/**
@@ -328,6 +322,7 @@
final TestAnimation animPast = new TestAnimation();
final TestAnimation animFuture = new TestAnimation();
+ delayTestFinish(50 * DELAY_MULTIPLIER);
// Run animations
double curTime = Duration.currentTimeMillis();
animNow.run(30 * DELAY_MULTIPLIER);
@@ -416,8 +411,6 @@
animFuture.assertStarted(true);
animFuture.assertCompleted(false);
animFuture.assertProgressRange(0.0, 1.0);
-
- finishTest();
}
}.schedule(35 * DELAY_MULTIPLIER);
@@ -440,8 +433,5 @@
finishTest();
}
}.schedule(45 * DELAY_MULTIPLIER);
-
- // Wait for the test to finish
- delayTestFinish(50 * DELAY_MULTIPLIER);
}
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java b/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
index 26357df..05e80d0 100644
--- a/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
@@ -46,7 +46,7 @@
}
// Repeated runAsync using a Timer
- public void runAsync1(final int attempt) {
+ private void runAsync1(final int attempt) {
log("runAsync1: attempt = " + attempt);
GWT.runAsync(new MyRunAsyncCallback() {
public void onFailure(Throwable caught) {
diff --git a/user/test/com/google/gwt/junit/BatchingStrategyTest.java b/user/test/com/google/gwt/junit/BatchingStrategyTest.java
index bd86c18..8a44b09 100644
--- a/user/test/com/google/gwt/junit/BatchingStrategyTest.java
+++ b/user/test/com/google/gwt/junit/BatchingStrategyTest.java
@@ -26,10 +26,35 @@
import java.util.Set;
/**
- * Tests of {@link BatchingStrategy}.
+ * Tests of {@link BatchingStrategy}. This test must run after a
+ * {@link GWTTestCase} to ensure that JUnitShell is already initialized.
*/
public class BatchingStrategyTest extends TestCase {
+ private static class TestClass0 {
+ public void testMethod0() {
+ }
+
+ public void testMethod1() {
+ }
+ }
+
+ private static class TestClass1 {
+ public void testMethod2() {
+ }
+
+ public void testMethod3() {
+ }
+
+ public void testMethod4() {
+ }
+ }
+
+ private static class TestClass2 {
+ public void testMethod5() {
+ }
+ }
+
/**
* The synthetic name of the module used for this test.
*/
@@ -41,17 +66,17 @@
private static TestModuleInfo fakeModuleInfo;
private static final TestInfo TEST_INFO_0_0 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass0", "testMethod0");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass0.class.getName(), "testMethod0");
private static final TestInfo TEST_INFO_0_1 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass0", "testMethod1");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass0.class.getName(), "testMethod1");
private static final TestInfo TEST_INFO_1_2 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod2");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod2");
private static final TestInfo TEST_INFO_1_3 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod3");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod3");
private static final TestInfo TEST_INFO_1_4 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod4");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod4");
private static final TestInfo TEST_INFO_2_5 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass2", "testMethod5");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass2.class.getName(), "testMethod5");
public void testClassBatchingStrategy() {
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
diff --git a/user/test/com/google/gwt/junit/JUnitSuite.java b/user/test/com/google/gwt/junit/JUnitSuite.java
index ec1c25b..40f468e 100644
--- a/user/test/com/google/gwt/junit/JUnitSuite.java
+++ b/user/test/com/google/gwt/junit/JUnitSuite.java
@@ -27,17 +27,19 @@
public static Test suite() {
GWTTestSuite suite = new GWTTestSuite("Test for suite for com.google.gwt.junit");
- suite.addTestSuite(FakeMessagesMakerTest.class);
- suite.addTestSuite(BatchingStrategyTest.class);
- suite.addTestSuite(JUnitMessageQueueTest.class);
- suite.addTestSuite(GWTTestCaseNoClientTest.class);
- suite.addTestSuite(BenchmarkNoClientTest.class);
-
// client
// Suppressed due to flakiness on Linux
// suite.addTestSuite(BenchmarkTest.class);
suite.addTestSuite(GWTTestCaseTest.class);
+ // Must run after a GWTTestCase so JUnitShell is initialized.
+ suite.addTestSuite(BatchingStrategyTest.class);
+
+ suite.addTestSuite(FakeMessagesMakerTest.class);
+ suite.addTestSuite(JUnitMessageQueueTest.class);
+ suite.addTestSuite(GWTTestCaseNoClientTest.class);
+ suite.addTestSuite(BenchmarkNoClientTest.class);
+
// These two are intended only to be run manually. See class comments
// suite.addTestSuite(ParallelRemoteTest.class);
// suite.addTestSuite(TestManualAsync.class);
diff --git a/user/test/com/google/gwt/resources/ResourcesSuite.java b/user/test/com/google/gwt/resources/ResourcesSuite.java
index 7826df2..98538b9 100644
--- a/user/test/com/google/gwt/resources/ResourcesSuite.java
+++ b/user/test/com/google/gwt/resources/ResourcesSuite.java
@@ -21,10 +21,10 @@
import com.google.gwt.resources.client.ImageResourceTest;
import com.google.gwt.resources.client.NestedBundleTest;
import com.google.gwt.resources.client.TextResourceTest;
+import com.google.gwt.resources.css.CssNodeClonerTest;
+import com.google.gwt.resources.css.CssReorderTest;
+import com.google.gwt.resources.css.CssRtlTest;
import com.google.gwt.resources.css.ExtractClassNamesVisitorTest;
-import com.google.gwt.resources.rg.CssNodeClonerTest;
-import com.google.gwt.resources.rg.CssReorderTest;
-import com.google.gwt.resources.rg.CssRtlTest;
import junit.framework.Test;
diff --git a/user/test/com/google/gwt/resources/client/CSSResourceTest.java b/user/test/com/google/gwt/resources/client/CSSResourceTest.java
index b0c4664..3bb69ec 100644
--- a/user/test/com/google/gwt/resources/client/CSSResourceTest.java
+++ b/user/test/com/google/gwt/resources/client/CSSResourceTest.java
@@ -135,6 +135,10 @@
@Strict
HasDescendants descendants();
+ // Make sure an empty, no-op CssResource works
+ @Strict
+ CssResource empty();
+
@Source("16x16.png")
ImageResource spriteMethod();
}
@@ -292,6 +296,17 @@
assertFalse("10".equals(defines.overrideIntClass()));
}
+ public void testEnsureInjected() {
+ Resources r = GWT.create(Resources.class);
+ assertTrue(r.empty().ensureInjected());
+
+ r = GWT.create(Resources.class);
+ assertFalse(r.empty().ensureInjected());
+
+ r = GWT.create(ChildResources.class);
+ assertTrue(r.empty().ensureInjected());
+ }
+
public void testMultipleBundles() {
Resources r1 = GWT.create(Resources.class);
SiblingResources r2 = GWT.create(SiblingResources.class);
diff --git a/user/test/com/google/gwt/resources/client/ImageResourceTest.java b/user/test/com/google/gwt/resources/client/ImageResourceTest.java
index 21e53fe..9da158a 100644
--- a/user/test/com/google/gwt/resources/client/ImageResourceTest.java
+++ b/user/test/com/google/gwt/resources/client/ImageResourceTest.java
@@ -113,6 +113,7 @@
assertEquals(a.getLeft(), b.getTop());
assertEquals(a.getLeft(), c.getTop());
+ delayTestFinish(1000);
// See if the size of the image strip is what we expect
Image i = new Image(a.getURL());
i.addLoadHandler(new LoadHandler() {
@@ -127,7 +128,6 @@
});
RootPanel.get().add(i);
- delayTestFinish(1000);
}
public void testPacking() {
diff --git a/user/test/com/google/gwt/resources/client/TextResourceTest.java b/user/test/com/google/gwt/resources/client/TextResourceTest.java
index 2b4ad40..2c9093f 100644
--- a/user/test/com/google/gwt/resources/client/TextResourceTest.java
+++ b/user/test/com/google/gwt/resources/client/TextResourceTest.java
@@ -47,6 +47,8 @@
public void testExternal() throws ResourceException {
final Resources r = GWT.create(Resources.class);
+ delayTestFinish(2000);
+
ResourceCallback<TextResource> c = new ResourceCallback<TextResource>() {
public void onError(ResourceException e) {
@@ -61,7 +63,6 @@
}
};
- delayTestFinish(2000);
r.helloWorldExternal().getText(c);
}
diff --git a/user/test/com/google/gwt/resources/client/empty.css b/user/test/com/google/gwt/resources/client/empty.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/user/test/com/google/gwt/resources/client/empty.css
diff --git a/user/test/com/google/gwt/resources/rg/CssNodeClonerTest.java b/user/test/com/google/gwt/resources/css/CssNodeClonerTest.java
similarity index 96%
rename from user/test/com/google/gwt/resources/rg/CssNodeClonerTest.java
rename to user/test/com/google/gwt/resources/css/CssNodeClonerTest.java
index 24c5042..517de81 100644
--- a/user/test/com/google/gwt/resources/rg/CssNodeClonerTest.java
+++ b/user/test/com/google/gwt/resources/css/CssNodeClonerTest.java
@@ -13,16 +13,16 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.resources.rg;
+package com.google.gwt.resources.css;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.resources.css.GenerateCssAst;
import com.google.gwt.resources.css.ast.CssNode;
import com.google.gwt.resources.css.ast.CssNodeCloner;
import com.google.gwt.resources.css.ast.CssProperty;
import com.google.gwt.resources.css.ast.CssSelector;
import com.google.gwt.resources.css.ast.CssStylesheet;
+import com.google.gwt.resources.rg.CssTestCase;
import java.net.URL;
import java.util.List;
diff --git a/user/test/com/google/gwt/resources/rg/CssReorderTest.java b/user/test/com/google/gwt/resources/css/CssReorderTest.java
similarity index 82%
rename from user/test/com/google/gwt/resources/rg/CssReorderTest.java
rename to user/test/com/google/gwt/resources/css/CssReorderTest.java
index 2777548..0b3a62e 100644
--- a/user/test/com/google/gwt/resources/rg/CssReorderTest.java
+++ b/user/test/com/google/gwt/resources/css/CssReorderTest.java
@@ -13,14 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.resources.rg;
+package com.google.gwt.resources.css;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.resources.css.ast.CssVisitor;
-import com.google.gwt.resources.rg.CssResourceGenerator.MergeIdenticalSelectorsVisitor;
-import com.google.gwt.resources.rg.CssResourceGenerator.MergeRulesByContentVisitor;
-import com.google.gwt.resources.rg.CssResourceGenerator.SplitRulesVisitor;
+import com.google.gwt.resources.rg.CssTestCase;
/**
* Tests CSS reordering visitors.
diff --git a/user/test/com/google/gwt/resources/rg/CssRtlTest.java b/user/test/com/google/gwt/resources/css/CssRtlTest.java
similarity index 94%
rename from user/test/com/google/gwt/resources/rg/CssRtlTest.java
rename to user/test/com/google/gwt/resources/css/CssRtlTest.java
index ac0bc8e..fa75951 100644
--- a/user/test/com/google/gwt/resources/rg/CssRtlTest.java
+++ b/user/test/com/google/gwt/resources/css/CssRtlTest.java
@@ -13,12 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.resources.rg;
+package com.google.gwt.resources.css;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.resources.css.ast.CssVisitor;
-import com.google.gwt.resources.rg.CssResourceGenerator.RtlVisitor;
+import com.google.gwt.resources.rg.CssTestCase;
/**
* This is a static test of the automatic RTL support.
diff --git a/user/test/com/google/gwt/resources/rg/backgroundProperties_expected.css b/user/test/com/google/gwt/resources/css/backgroundProperties_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/backgroundProperties_expected.css
rename to user/test/com/google/gwt/resources/css/backgroundProperties_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/backgroundProperties_test.css b/user/test/com/google/gwt/resources/css/backgroundProperties_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/backgroundProperties_test.css
rename to user/test/com/google/gwt/resources/css/backgroundProperties_test.css
diff --git a/user/test/com/google/gwt/resources/rg/cursorProperties_expected.css b/user/test/com/google/gwt/resources/css/cursorProperties_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/cursorProperties_expected.css
rename to user/test/com/google/gwt/resources/css/cursorProperties_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/cursorProperties_test.css b/user/test/com/google/gwt/resources/css/cursorProperties_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/cursorProperties_test.css
rename to user/test/com/google/gwt/resources/css/cursorProperties_test.css
diff --git a/user/test/com/google/gwt/resources/rg/directionProperty_expected.css b/user/test/com/google/gwt/resources/css/directionProperty_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/directionProperty_expected.css
rename to user/test/com/google/gwt/resources/css/directionProperty_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/directionProperty_test.css b/user/test/com/google/gwt/resources/css/directionProperty_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/directionProperty_test.css
rename to user/test/com/google/gwt/resources/css/directionProperty_test.css
diff --git a/user/test/com/google/gwt/resources/rg/fourValuedProperties_expected.css b/user/test/com/google/gwt/resources/css/fourValuedProperties_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/fourValuedProperties_expected.css
rename to user/test/com/google/gwt/resources/css/fourValuedProperties_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/fourValuedProperties_test.css b/user/test/com/google/gwt/resources/css/fourValuedProperties_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/fourValuedProperties_test.css
rename to user/test/com/google/gwt/resources/css/fourValuedProperties_test.css
diff --git a/user/test/com/google/gwt/resources/rg/leftRightProperties_expected.css b/user/test/com/google/gwt/resources/css/leftRightProperties_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/leftRightProperties_expected.css
rename to user/test/com/google/gwt/resources/css/leftRightProperties_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/leftRightProperties_test.css b/user/test/com/google/gwt/resources/css/leftRightProperties_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/leftRightProperties_test.css
rename to user/test/com/google/gwt/resources/css/leftRightProperties_test.css
diff --git a/user/test/com/google/gwt/resources/rg/noflip_expected.css b/user/test/com/google/gwt/resources/css/noflip_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/noflip_expected.css
rename to user/test/com/google/gwt/resources/css/noflip_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/noflip_test.css b/user/test/com/google/gwt/resources/css/noflip_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/noflip_test.css
rename to user/test/com/google/gwt/resources/css/noflip_test.css
diff --git a/user/test/com/google/gwt/resources/rg/propertyMerging_expected.css b/user/test/com/google/gwt/resources/css/propertyMerging_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/propertyMerging_expected.css
rename to user/test/com/google/gwt/resources/css/propertyMerging_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/propertyMerging_test.css b/user/test/com/google/gwt/resources/css/propertyMerging_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/propertyMerging_test.css
rename to user/test/com/google/gwt/resources/css/propertyMerging_test.css
diff --git a/user/test/com/google/gwt/resources/rg/selectorMerging_expected.css b/user/test/com/google/gwt/resources/css/selectorMerging_expected.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/selectorMerging_expected.css
rename to user/test/com/google/gwt/resources/css/selectorMerging_expected.css
diff --git a/user/test/com/google/gwt/resources/rg/selectorMerging_test.css b/user/test/com/google/gwt/resources/css/selectorMerging_test.css
similarity index 100%
rename from user/test/com/google/gwt/resources/rg/selectorMerging_test.css
rename to user/test/com/google/gwt/resources/css/selectorMerging_test.css
diff --git a/user/test/com/google/gwt/resources/rg/CssTestCase.java b/user/test/com/google/gwt/resources/rg/CssTestCase.java
index 01e7555..33cbc0b 100644
--- a/user/test/com/google/gwt/resources/rg/CssTestCase.java
+++ b/user/test/com/google/gwt/resources/rg/CssTestCase.java
@@ -38,13 +38,17 @@
* modifications to the CSS AST.
*/
public class CssTestCase extends TestCase {
+ /*
+ * NB: This class is in the resources.rg package so that it can acess
+ * package-protected methods in CssResourceGenerator.
+ */
/**
* Triggers an assertion if a CssNode is traversed more than once.
*
* @see CssTestCase#assertNoAliasing(CssNode)
*/
- protected static class AliasDetector extends CssVisitor {
+ public static class AliasDetector extends CssVisitor {
private final Map<CssNode, Void> seen = new IdentityHashMap<CssNode, Void>();
@Override
diff --git a/user/test/com/google/gwt/user/client/CommandExecutorTest.java b/user/test/com/google/gwt/user/client/CommandExecutorTest.java
index ca18dc7..1e970d9 100644
--- a/user/test/com/google/gwt/user/client/CommandExecutorTest.java
+++ b/user/test/com/google/gwt/user/client/CommandExecutorTest.java
@@ -114,13 +114,13 @@
}
});
+ delayTestFinish(TEST_FINISH_DELAY_MILLIS);
ce.submit(new Command() {
public void execute() {
finishTest();
}
});
- delayTestFinish(TEST_FINISH_DELAY_MILLIS);
ce.doExecuteCommands(Duration.currentTimeMillis());
}
};
diff --git a/user/test/com/google/gwt/user/client/CookieTest.java b/user/test/com/google/gwt/user/client/CookieTest.java
index 7ecef1b..a51ef3d 100644
--- a/user/test/com/google/gwt/user/client/CookieTest.java
+++ b/user/test/com/google/gwt/user/client/CookieTest.java
@@ -76,6 +76,7 @@
Cookies.setCookie(lateCookie, "late", expiresLate);
Cookies.setCookie(sessionCookie, "forever", null);
+ delayTestFinish(6 * 1000);
// Wait until the cookie expires before checking it
Timer timer = new Timer() {
@Override
@@ -96,7 +97,6 @@
}
};
timer.schedule(5010);
- delayTestFinish(6 * 1000);
}
/**
diff --git a/user/test/com/google/gwt/user/client/WindowTest.java b/user/test/com/google/gwt/user/client/WindowTest.java
index f25219c..b50e698 100644
--- a/user/test/com/google/gwt/user/client/WindowTest.java
+++ b/user/test/com/google/gwt/user/client/WindowTest.java
@@ -149,6 +149,7 @@
final Label largeDOM = new Label();
largeDOM.setPixelSize(oldClientWidth + 100, oldClientHeight + 100);
RootPanel.get().add(largeDOM);
+ delayTestFinish(200);
DeferredCommand.addCommand(new Command() {
public void execute() {
int newClientHeight = Window.getClientHeight();
@@ -159,7 +160,6 @@
finishTest();
}
});
- delayTestFinish(200);
}
/**
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
index 6023899..6544b75 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
@@ -180,6 +180,7 @@
}
public void testSerializationExceptionPreventsCall() {
+ delayTestFinish(TEST_DELAY);
final boolean serializationExceptionCaught[] = new boolean[1];
new Timer() {
@Override
@@ -189,7 +190,6 @@
finishTest();
}
}.schedule(TEST_DELAY / 2);
- delayTestFinish(TEST_DELAY);
InheritanceTestServiceAsync service = getServiceAsync();
service.echo(new AnonymousClassInterface() {
diff --git a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
index d794eea..3cc558c 100644
--- a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
@@ -102,6 +102,7 @@
UIObjectTest.assertDebugId("myDialogBox-content",
DOM.getParent(content.getElement()));
+ delayTestFinish(250);
// Check the header IDs
DeferredCommand.addCommand(new Command() {
public void execute() {
@@ -110,7 +111,6 @@
finishTest();
}
});
- delayTestFinish(250);
}
@Override
diff --git a/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java b/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
index 8e12014..98f8eb5 100644
--- a/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DisclosurePanelTest.java
@@ -48,6 +48,7 @@
panel.setOpen(true);
+ delayTestFinish(500);
// Allow the animation time to finish
Timer t = new Timer() {
@Override
@@ -59,7 +60,6 @@
}
};
t.schedule(450);
- delayTestFinish(500);
}
public void testAttachDetachOrder() {
diff --git a/user/test/com/google/gwt/user/client/ui/HistoryTest.java b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
index 34f5373..0d1bd85 100644
--- a/user/test/com/google/gwt/user/client/ui/HistoryTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
@@ -125,6 +125,7 @@
* Verify that no events are issued via newItem if there were not reqeuested.
*/
public void testNoEvents() {
+ delayTestFinish(5000);
addHistoryListenerImpl(new HistoryListener() {
{
timer = new Timer() {
@@ -139,7 +140,6 @@
fail("onHistoryChanged should not have been called");
}
});
- delayTestFinish(5000);
History.newItem("testNoEvents", false);
}
@@ -197,9 +197,10 @@
* called once per {@link History#newItem(String)}.
*/
public void testHistoryChangedCount() {
+ delayTestFinish(5000);
timer = new Timer() {
private int count = 0;
-
+
public void run() {
if (count++ == 0) {
// verify that duplicates don't issue another event
@@ -222,7 +223,6 @@
timer.schedule(500);
}
});
- delayTestFinish(5000);
History.newItem("testHistoryChangedCount");
}
diff --git a/user/test/com/google/gwt/user/client/ui/ImageTest.java b/user/test/com/google/gwt/user/client/ui/ImageTest.java
index 995c57d..156feae 100644
--- a/user/test/com/google/gwt/user/client/ui/ImageTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ImageTest.java
@@ -99,6 +99,7 @@
final Image image = new Image("counting-forwards.png", 12, 13, 8, 8);
assertEquals("clipped", getCurrentImageStateName(image));
+ delayTestFinish(5000);
image.addLoadListener(new LoadListener() {
private int onLoadEventCount = 0;
@@ -121,7 +122,6 @@
}
});
- delayTestFinish(5000);
RootPanel.get().add(image);
}
@@ -134,6 +134,7 @@
final Image image = new Image("counting-forwards.png");
assertEquals("unclipped", getCurrentImageStateName(image));
+ delayTestFinish(5000);
image.addLoadListener(new LoadListener() {
private int onLoadEventCount = 0;
@@ -157,7 +158,6 @@
}
});
- delayTestFinish(5000);
RootPanel.get().add(image);
}
@@ -169,6 +169,7 @@
public void disabledTestCreateImage() {
final Image image = new Image("counting-forwards.png");
+ delayTestFinish(5000);
image.addLoadListener(new LoadListener() {
private int onLoadEventCount = 0;
@@ -185,7 +186,6 @@
}
});
- delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals(0, image.getOriginLeft());
assertEquals(0, image.getOriginTop());
@@ -202,6 +202,7 @@
public void disabledTestSetUrlAndLoadEventsOnUnclippedImage() {
final Image image = new Image();
+ delayTestFinish(5000);
image.addLoadListener(new LoadListener() {
private int onLoadEventCount = 0;
@@ -218,7 +219,6 @@
}
});
- delayTestFinish(5000);
RootPanel.get().add(image);
image.setUrl("counting-backwards.png");
}
@@ -233,6 +233,7 @@
public void disabledTestSetUrlAndVisibleRectOnUnclippedImage() {
final Image image = new Image("counting-backwards.png");
+ delayTestFinish(5000);
image.addLoadListener(new LoadListener() {
private int onLoadEventCount = 0;
@@ -256,7 +257,6 @@
}
});
- delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals("unclipped", getCurrentImageStateName(image));
}
@@ -273,6 +273,7 @@
public void testCreateClippedImage() {
final Image image = new Image("counting-forwards.png", 16, 16, 16, 16);
+ delayTestFinish(5000);
final TestLoadListener listener = new TestLoadListener(image) {
private int onLoadEventCount = 0;
@@ -303,7 +304,6 @@
});
image.addErrorHandler(new TestErrorHandler(image));
- delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals(16, image.getOriginLeft());
assertEquals(16, image.getOriginTop());
@@ -344,6 +344,7 @@
@DoNotRunWith({Platform.Htmlunit})
public void testSetUrlAndVisibleRectOnClippedImage() {
final Image image = new Image("counting-backwards.png", 12, 12, 12, 12);
+ delayTestFinish(5000);
final TestLoadListener listener = new TestLoadListener(image) {
private int onLoadEventCount = 0;
@@ -381,7 +382,6 @@
});
image.addErrorHandler(new TestErrorHandler(image));
- delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals("clipped", getCurrentImageStateName(image));
image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16, 16);
@@ -396,6 +396,7 @@
public void testSetVisibleRectAndLoadEventsOnClippedImage() {
final Image image = new Image("counting-backwards.png", 16, 16, 16, 16);
+ delayTestFinish(5000);
final TestLoadListener listener = new TestLoadListener(image) {
private int onLoadEventCount = 0;
@@ -422,7 +423,6 @@
});
image.addErrorHandler(new TestErrorHandler(image));
- delayTestFinish(5000);
RootPanel.get().add(image);
image.setVisibleRect(0, 0, 16, 16);
image.setVisibleRect(0, 0, 16, 16);
diff --git a/user/test/com/google/gwt/user/client/ui/ListBoxTest.java b/user/test/com/google/gwt/user/client/ui/ListBoxTest.java
index 5b116de..97e9501 100644
--- a/user/test/com/google/gwt/user/client/ui/ListBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ListBoxTest.java
@@ -49,6 +49,7 @@
list.ensureDebugId("myList");
UIObjectTest.assertDebugId("myList", list.getElement());
+ delayTestFinish(250);
DeferredCommand.addCommand(new Command() {
public void execute() {
UIObjectTest.assertDebugIdContents("myList-item0", "option0");
@@ -58,7 +59,6 @@
finishTest();
}
});
- delayTestFinish(250);
}
public void testInsert() {
diff --git a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
index 1785aeb..a33f64c 100644
--- a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
+++ b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
@@ -236,6 +236,7 @@
bar.ensureDebugId("myMenu");
UIObjectTest.assertDebugId("myMenu", bar.getElement());
+ delayTestFinish(250);
DeferredCommand.addCommand(new Command() {
public void execute() {
UIObjectTest.assertDebugIdContents("myMenu-item0", "top0");
@@ -248,7 +249,6 @@
finishTest();
}
});
- delayTestFinish(250);
}
/**
diff --git a/user/test/com/google/gwt/user/client/ui/PopupTest.java b/user/test/com/google/gwt/user/client/ui/PopupTest.java
index 0ec6231..eb64dc0 100644
--- a/user/test/com/google/gwt/user/client/ui/PopupTest.java
+++ b/user/test/com/google/gwt/user/client/ui/PopupTest.java
@@ -333,6 +333,7 @@
}
}.schedule(1000);
+ delayTestFinish(5000);
// Give time for any errors to occur
new Timer() {
@Override
@@ -340,7 +341,5 @@
finishTest();
}
}.schedule(2000);
-
- delayTestFinish(5000);
}
}
diff --git a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
index cce59a8..d504f19 100644
--- a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
@@ -228,6 +228,7 @@
public void testSetTextBeforeInit() {
final RichTextArea richTextArea = new RichTextArea();
richTextArea.setText("foo");
+ delayTestFinish(RICH_TEXT_ASYNC_DELAY);
richTextArea.addInitializeHandler(new InitializeHandler() {
public void onInitialize(InitializeEvent event) {
assertEquals("foo", richTextArea.getText());
@@ -236,6 +237,5 @@
});
RootPanel.get().add(richTextArea);
assertEquals("foo", richTextArea.getText());
- delayTestFinish(RICH_TEXT_ASYNC_DELAY);
}
}
diff --git a/user/test/com/google/gwt/user/client/ui/StackPanelTest.java b/user/test/com/google/gwt/user/client/ui/StackPanelTest.java
index 0e6ab61..4bf82e6 100644
--- a/user/test/com/google/gwt/user/client/ui/StackPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/StackPanelTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 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
@@ -75,6 +75,8 @@
UIObjectTest.assertDebugId("myStack-content2",
DOM.getParent(c.getElement()));
+ delayTestFinish(5000);
+
// Check the header IDs
DeferredCommand.addCommand(new Command() {
public void execute() {
@@ -97,7 +99,6 @@
finishTest();
}
});
- delayTestFinish(5000);
}
/**
diff --git a/user/test/com/google/gwt/user/client/ui/TabPanelTest.java b/user/test/com/google/gwt/user/client/ui/TabPanelTest.java
index 75c634e..0db70a3 100644
--- a/user/test/com/google/gwt/user/client/ui/TabPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/TabPanelTest.java
@@ -202,6 +202,7 @@
p.add(new Button("foo"), "foo");
p.add(new Button("bar"), "bar");
+ this.delayTestFinish(1000);
// Make sure selecting a tab fires both events in the right order.
p.addTabListener(new TabListener() {
private boolean onBeforeFired;
@@ -217,7 +218,6 @@
}
});
- this.delayTestFinish(1000);
p.selectTab(1);
}