com.google.gwt.resources.rg.GssResourceGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vaadin-client Show documentation
Show all versions of vaadin-client Show documentation
Vaadin is a web application framework for Rich Internet Applications (RIA).
Vaadin enables easy development and maintenance of fast and
secure rich web
applications with a stunning look and feel and a wide browser support.
It features a server-side architecture with the majority of the logic
running
on the server. Ajax technology is used at the browser-side to ensure a
rich
and interactive user experience.
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.resources.rg;
import com.google.gwt.core.ext.BadPropertyValueException;
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.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.util.Util;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.resources.client.CssResource;
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.ResourcePrototype;
import com.google.gwt.resources.converter.Css2Gss;
import com.google.gwt.resources.converter.Css2GssConversionException;
import com.google.gwt.resources.ext.ClientBundleRequirements;
import com.google.gwt.resources.ext.ResourceContext;
import com.google.gwt.resources.ext.ResourceGeneratorUtil;
import com.google.gwt.resources.ext.SupportsGeneratorResultCaching;
import com.google.gwt.resources.gss.CreateRuntimeConditionalNodes;
import com.google.gwt.resources.gss.CssPrinter;
import com.google.gwt.resources.gss.ExtendedEliminateConditionalNodes;
import com.google.gwt.resources.gss.ExternalClassesCollector;
import com.google.gwt.resources.gss.GwtGssFunctionMapProvider;
import com.google.gwt.resources.gss.ImageSpriteCreator;
import com.google.gwt.resources.gss.PermutationsCollector;
import com.google.gwt.resources.gss.RecordingBidiFlipper;
import com.google.gwt.resources.gss.RenamingSubstitutionMap;
import com.google.gwt.resources.gss.RuntimeConditionalBlockCollector;
import com.google.gwt.resources.gss.ValidateRuntimeConditionalNode;
import com.google.gwt.resources.rg.CssResourceGenerator.JClassOrderComparator;
import com.google.gwt.thirdparty.common.css.MinimalSubstitutionMap;
import com.google.gwt.thirdparty.common.css.PrefixingSubstitutionMap;
import com.google.gwt.thirdparty.common.css.SourceCode;
import com.google.gwt.thirdparty.common.css.SourceCodeLocation;
import com.google.gwt.thirdparty.common.css.SubstitutionMap;
import com.google.gwt.thirdparty.common.css.compiler.ast.CssDefinitionNode;
import com.google.gwt.thirdparty.common.css.compiler.ast.CssNumericNode;
import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree;
import com.google.gwt.thirdparty.common.css.compiler.ast.CssValueNode;
import com.google.gwt.thirdparty.common.css.compiler.ast.ErrorManager;
import com.google.gwt.thirdparty.common.css.compiler.ast.GssError;
import com.google.gwt.thirdparty.common.css.compiler.ast.GssFunction;
import com.google.gwt.thirdparty.common.css.compiler.ast.GssParser;
import com.google.gwt.thirdparty.common.css.compiler.ast.GssParserException;
import com.google.gwt.thirdparty.common.css.compiler.passes.AbbreviatePositionalValues;
import com.google.gwt.thirdparty.common.css.compiler.passes.CheckDependencyNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.CollectConstantDefinitions;
import com.google.gwt.thirdparty.common.css.compiler.passes.CollectMixinDefinitions;
import com.google.gwt.thirdparty.common.css.compiler.passes.ColorValueOptimizer;
import com.google.gwt.thirdparty.common.css.compiler.passes.ConstantDefinitions;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateComponentNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateConditionalNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateConstantReferences;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateDefinitionNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateMixins;
import com.google.gwt.thirdparty.common.css.compiler.passes.CreateStandardAtRuleNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.CssClassRenaming;
import com.google.gwt.thirdparty.common.css.compiler.passes.DisallowDuplicateDeclarations;
import com.google.gwt.thirdparty.common.css.compiler.passes.EliminateEmptyRulesetNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.EliminateUnitsFromZeroNumericValues;
import com.google.gwt.thirdparty.common.css.compiler.passes.EliminateUselessRulesetNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.HandleUnknownAtRuleNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.MarkRemovableRulesetNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.MergeAdjacentRulesetNodesWithSameDeclarations;
import com.google.gwt.thirdparty.common.css.compiler.passes.MergeAdjacentRulesetNodesWithSameSelector;
import com.google.gwt.thirdparty.common.css.compiler.passes.ProcessComponents;
import com.google.gwt.thirdparty.common.css.compiler.passes.ProcessKeyframes;
import com.google.gwt.thirdparty.common.css.compiler.passes.ProcessRefiners;
import com.google.gwt.thirdparty.common.css.compiler.passes.ReplaceConstantReferences;
import com.google.gwt.thirdparty.common.css.compiler.passes.ReplaceMixins;
import com.google.gwt.thirdparty.common.css.compiler.passes.ResolveCustomFunctionNodes;
import com.google.gwt.thirdparty.common.css.compiler.passes.SplitRulesetNodes;
import com.google.gwt.thirdparty.guava.common.base.CaseFormat;
import com.google.gwt.thirdparty.guava.common.base.Charsets;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
import com.google.gwt.thirdparty.guava.common.base.Predicates;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet.Builder;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.io.Resources;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.rebind.StringSourceWriter;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
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.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.zip.Adler32;
/**
* This generator parses and compiles a GSS file to a css string and generates the implementation
* of the corresponding CssResource interface.
*/
public class GssResourceGenerator extends AbstractCssResourceGenerator implements
SupportsGeneratorResultCaching {
/**
* {@link ErrorManager} used to log the errors and warning messages produced by the different
* {@link com.google.gwt.thirdparty.common.css.compiler.ast.CssCompilerPass}.
*/
private static class LoggerErrorManager implements ErrorManager {
private final TreeLogger logger;
private boolean hasErrors;
private LoggerErrorManager(TreeLogger logger) {
this.logger = logger;
}
@Override
public void generateReport() {
// do nothing
}
@Override
public boolean hasErrors() {
return hasErrors;
}
@Override
public void report(GssError error) {
String fileName = "";
String location = "";
SourceCodeLocation codeLocation = error.getLocation();
if (codeLocation != null) {
fileName = codeLocation.getSourceCode().getFileName();
location = "[line: " + codeLocation.getBeginLineNumber() + " column: " + codeLocation
.getBeginIndexInLine() + "]";
}
logger.log(Type.ERROR, "Error in " + fileName + location + ": " + error.getMessage());
hasErrors = true;
}
@Override
public void reportWarning(GssError warning) {
logger.log(Type.WARN, warning.getMessage());
}
}
private static class ConversionResult {
final String gss;
final Map defNameMapping;
private ConversionResult(String gss, Map defNameMapping) {
this.gss = gss;
this.defNameMapping = defNameMapping;
}
}
private static class RenamingResult {
final Map mapping;
final Set externalClassCandidate;
private RenamingResult(Map mapping, Set externalClassCandidate) {
this.mapping = mapping;
this.externalClassCandidate = externalClassCandidate;
}
}
private static class CssParsingResult {
final CssTree tree;
final List permutationAxes;
final Map originalConstantNameMapping;
private CssParsingResult(CssTree tree, List permutationAxis,
Map originalConstantNameMapping) {
this.tree = tree;
this.permutationAxes = permutationAxis;
this.originalConstantNameMapping = originalConstantNameMapping;
}
}
// To be sure to avoid conflict during the style classes renaming between different GssResources,
// we will create a different prefix for each GssResource. We use a MinimalSubstitutionMap
// that will create a String with 1-6 characters in length but keeping the length of the prefix
// as short as possible. For instance if we have two GssResources to compile, the prefix
// for the first resource will be 'a' and the prefix for the second resource will be 'b' and so on
private static final SubstitutionMap resourcePrefixBuilder = new MinimalSubstitutionMap();
private static final String KEY_LEGACY = "CssResource.legacy";
private static final String KEY_CONVERSION_MODE = "CssResource.conversionMode";
private static final String KEY_STYLE = "CssResource.style";
private static final String ALLOWED_AT_RULE = "CssResource.allowedAtRules";
private static final String ALLOWED_FUNCTIONS = "CssResource.allowedFunctions";
private static final String KEY_OBFUSCATION_PREFIX = "CssResource.obfuscationPrefix";
private static final String KEY_CLASS_PREFIX = "cssResourcePrefix";
private static final String KEY_BY_CLASS_AND_METHOD = "cssResourceClassAndMethod";
private static final String KEY_HAS_CACHED_DATA = "hasCachedData";
private static final String KEY_SHARED_METHODS = "sharedMethods";
private static final char[] BASE32_CHARS = new char[]{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', '0', '1',
'2', '3', '4', '5', '6'};
/**
* Returns the import prefix for a type, including the trailing hyphen.
*/
public static String getImportPrefix(JClassType importType) {
String prefix = importType.getSimpleSourceName();
ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class);
if (exp != null) {
prefix = exp.value();
}
return prefix + "-";
}
private static String encode(long id) {
assert id >= 0;
StringBuilder b = new StringBuilder();
// Use only guaranteed-alpha characters for the first character
b.append(BASE32_CHARS[(int) (id & 0xf)]);
id >>= 4;
while (id != 0) {
b.append(BASE32_CHARS[(int) (id & 0x1f)]);
id >>= 5;
}
return b.toString();
}
private Map cssParsingResultMap;
private Set allowedNonStandardFunctions;
private LoggerErrorManager errorManager;
private JMethod getTextMethod;
private JMethod ensuredInjectedMethod;
private JMethod getNameMethod;
private String obfuscationPrefix;
private CssObfuscationStyle obfuscationStyle;
private Set allowedAtRules;
private Map> replacementsByClassAndMethod;
private Map replacementsForSharedMethods;
private boolean allowLegacy;
private boolean lenientConversion;
@Override
public String createAssignment(TreeLogger logger, ResourceContext context, JMethod method)
throws UnableToCompleteException {
CssParsingResult cssParsingResult = cssParsingResultMap.get(method);
CssTree cssTree = cssParsingResult.tree;
RenamingResult renamingResult = doClassRenaming(cssTree, method, logger, context);
// TODO : Should we foresee configuration properties for simplifyCss and eliminateDeadCode
// booleans ?
ConstantDefinitions constantDefinitions = optimizeTree(cssParsingResult, context, true, true,
logger);
checkErrors();
Set externalClasses = revertRenamingOfExternalClasses(cssTree, renamingResult);
checkErrors();
// Validate that classes not assigned to one of the interface methods are external
validateExternalClasses(externalClasses, renamingResult.externalClassCandidate, method, logger);
SourceWriter sw = new StringSourceWriter();
sw.println("new " + method.getReturnType().getQualifiedSourceName() + "() {");
sw.indent();
writeMethods(logger, context, method, sw, constantDefinitions,
cssParsingResult.originalConstantNameMapping, renamingResult.mapping);
sw.outdent();
sw.println("}");
return sw.toString();
}
private void validateExternalClasses(Set externalClasses,
Set externalClassCandidates, JMethod method,
TreeLogger logger) throws UnableToCompleteException {
if (!isStrictResource(method)) {
return;
}
boolean hasError = false;
for (String candidate : externalClassCandidates) {
if (!externalClasses.contains(candidate)) {
logger.log(Type.ERROR, "The following non-obfuscated class is present in a strict " +
"CssResource: " + candidate);
hasError = true;
}
}
if (hasError) {
throw new UnableToCompleteException();
}
}
@Override
public void init(TreeLogger logger, ResourceContext context) throws UnableToCompleteException {
cssParsingResultMap = new IdentityHashMap();
errorManager = new LoggerErrorManager(logger);
allowedNonStandardFunctions = new HashSet();
allowedAtRules = Sets.newHashSet(ExternalClassesCollector.EXTERNAL_AT_RULE);
try {
PropertyOracle propertyOracle = context.getGeneratorContext().getPropertyOracle();
ConfigurationProperty styleProp = propertyOracle.getConfigurationProperty(KEY_STYLE);
obfuscationStyle = CssObfuscationStyle.getObfuscationStyle(styleProp.getValues().get(0));
obfuscationPrefix = getObfuscationPrefix(propertyOracle, context);
ConfigurationProperty allowedAtRuleProperty = propertyOracle
.getConfigurationProperty(ALLOWED_AT_RULE);
allowedAtRules.addAll(allowedAtRuleProperty.getValues());
ConfigurationProperty allowedFunctionsProperty = propertyOracle
.getConfigurationProperty(ALLOWED_FUNCTIONS);
allowedNonStandardFunctions.addAll(allowedFunctionsProperty.getValues());
allowLegacy = "true".equals(propertyOracle.getConfigurationProperty(KEY_LEGACY).getValues()
.get(0));
// enable lenient conversion when legacy mode is enabled
lenientConversion = allowLegacy && "lenient".equals(propertyOracle
.getConfigurationProperty(KEY_CONVERSION_MODE).getValues().get(0));
ClientBundleRequirements requirements = context.getRequirements();
requirements.addConfigurationProperty(KEY_STYLE);
requirements.addConfigurationProperty(KEY_OBFUSCATION_PREFIX);
requirements.addConfigurationProperty(ALLOWED_AT_RULE);
requirements.addConfigurationProperty(ALLOWED_FUNCTIONS);
requirements.addConfigurationProperty(KEY_LEGACY);
requirements.addConfigurationProperty(KEY_CONVERSION_MODE);
} catch (BadPropertyValueException e) {
logger.log(TreeLogger.ERROR, "Unable to query module property", e);
throw new UnableToCompleteException();
}
TypeOracle typeOracle = context.getGeneratorContext().getTypeOracle();
JClassType cssResourceInterface = typeOracle.findType(CssResource.class.getCanonicalName());
JClassType resourcePrototypeInterface = typeOracle.findType(ResourcePrototype.class
.getCanonicalName());
try {
getTextMethod = cssResourceInterface.getMethod("getText", new JType[0]);
ensuredInjectedMethod = cssResourceInterface.getMethod("ensureInjected", new JType[0]);
getNameMethod = resourcePrototypeInterface.getMethod("getName", new JType[0]);
} catch (NotFoundException e) {
logger.log(TreeLogger.ERROR, "Unable to lookup methods from CssResource and " +
"ResourcePrototype interface", e);
throw new UnableToCompleteException();
}
initReplacement(context);
}
private void initReplacement(ResourceContext context) {
if (context.getCachedData(KEY_HAS_CACHED_DATA, Boolean.class) != Boolean.TRUE) {
context.putCachedData(KEY_SHARED_METHODS, new IdentityHashMap());
context.putCachedData(KEY_BY_CLASS_AND_METHOD, new IdentityHashMap>());
context.putCachedData(KEY_HAS_CACHED_DATA, Boolean.TRUE);
}
replacementsByClassAndMethod = context.getCachedData(KEY_BY_CLASS_AND_METHOD, Map.class);
replacementsForSharedMethods = context.getCachedData(KEY_SHARED_METHODS, Map.class);
}
private String getObfuscationPrefix(PropertyOracle propertyOracle, ResourceContext context)
throws BadPropertyValueException {
String prefix = propertyOracle.getConfigurationProperty(KEY_OBFUSCATION_PREFIX)
.getValues().get(0);
if ("empty".equalsIgnoreCase(prefix)) {
return "";
} else if ("default".equalsIgnoreCase(prefix)) {
return getDefaultObfuscationPrefix(context);
}
return prefix;
}
private String getDefaultObfuscationPrefix(ResourceContext context) {
String prefix = context.getCachedData(KEY_CLASS_PREFIX, String.class);
if (prefix == null) {
prefix = computeDefaultPrefix(context);
context.putCachedData(KEY_CLASS_PREFIX, prefix);
}
return prefix;
}
private String computeDefaultPrefix(ResourceContext context) {
SortedSet gssResources = computeOperableTypes(context);
Adler32 checksum = new Adler32();
for (JClassType type : gssResources) {
checksum.update(Util.getBytes(type.getQualifiedSourceName()));
}
int seed = Math.abs((int) checksum.getValue());
return encode(seed) + "-";
}
private SortedSet computeOperableTypes(ResourceContext context) {
TypeOracle typeOracle = context.getGeneratorContext().getTypeOracle();
JClassType baseInterface = typeOracle.findType(CssResource.class.getCanonicalName());
SortedSet toReturn = new TreeSet(new JClassOrderComparator());
JClassType[] cssResourceSubtypes = baseInterface.getSubtypes();
for (JClassType type : cssResourceSubtypes) {
if (type.isInterface() != null) {
toReturn.add(type);
}
}
return toReturn;
}
@Override
public void prepare(TreeLogger logger, ResourceContext context,
ClientBundleRequirements requirements, JMethod method) throws UnableToCompleteException {
if (method.getReturnType().isInterface() == null) {
logger.log(TreeLogger.ERROR, "Return type must be an interface");
throw new UnableToCompleteException();
}
URL[] resourceUrls = ResourceGeneratorUtil.findResources(logger, context, method);
if (resourceUrls.length == 0) {
logger.log(TreeLogger.ERROR, "At least one source must be specified");
throw new UnableToCompleteException();
}
CssParsingResult cssParsingResult = parseResources(Lists.newArrayList(resourceUrls), logger);
cssParsingResultMap.put(method, cssParsingResult);
for (String permutationAxis : cssParsingResult.permutationAxes) {
try {
context.getRequirements().addPermutationAxis(permutationAxis);
} catch (BadPropertyValueException e) {
logger.log(TreeLogger.ERROR, "Unknown deferred-binding property " + permutationAxis, e);
throw new UnableToCompleteException();
}
}
}
@Override
protected String getCssExpression(TreeLogger logger, ResourceContext context,
JMethod method) throws UnableToCompleteException {
CssTree cssTree = cssParsingResultMap.get(method).tree;
String standard = printCssTree(cssTree);
// TODO add configuration properties for swapLtrRtlInUrl, swapLeftRightInUrl and
// shouldFlipConstantReferences booleans
RecordingBidiFlipper recordingBidiFlipper =
new RecordingBidiFlipper(cssTree.getMutatingVisitController(), false, false, true);
recordingBidiFlipper.runPass();
if (recordingBidiFlipper.nodeFlipped()) {
String reversed = printCssTree(cssTree);
return LocaleInfo.class.getName() + ".getCurrentLocale().isRTL() ? "
+ reversed + " : " + standard;
} else {
return standard;
}
}
private void checkErrors() throws UnableToCompleteException {
if (errorManager.hasErrors()) {
throw new UnableToCompleteException();
}
}
private RenamingResult doClassRenaming(CssTree cssTree, JMethod method, TreeLogger logger,
ResourceContext context) throws UnableToCompleteException {
Map> replacementsWithPrefix = computeReplacements(method, logger,
context);
RenamingSubstitutionMap substitutionMap = new RenamingSubstitutionMap(replacementsWithPrefix);
new CssClassRenaming(cssTree.getMutatingVisitController(), substitutionMap, null).runPass();
Map mapping = replacementsWithPrefix.get("");
mapping = Maps.newHashMap(Maps.filterKeys(mapping, Predicates.in(substitutionMap
.getStyleClasses())));
return new RenamingResult(mapping, substitutionMap.getExternalClassCandidates());
}
/**
* When the tree is fully processed, we can now collect the external classes and revert the
* renaming for these classes. We cannot collect the external classes during the original renaming
* because some external at-rule could be located inside a conditional block and could be
* removed when these blocks are evaluated.
*/
private Set revertRenamingOfExternalClasses(CssTree cssTree, RenamingResult renamingResult) {
ExternalClassesCollector externalClassesCollector = new ExternalClassesCollector(cssTree
.getMutatingVisitController(), errorManager);
externalClassesCollector.runPass();
Map styleClassesMapping = renamingResult.mapping;
// set containing all the style classes before the renaming.
Set allStyleClassSet = Sets.newHashSet(styleClassesMapping.keySet());
// add the style classes that aren't associated to a method
allStyleClassSet.addAll(renamingResult.externalClassCandidate);
Set externalClasses = externalClassesCollector.getExternalClassNames(allStyleClassSet,
renamingResult.externalClassCandidate);
final Map revertMap = new HashMap(externalClasses.size());
for (String external : externalClasses) {
revertMap.put(styleClassesMapping.get(external), external);
// override the mapping
styleClassesMapping.put(external, external);
}
SubstitutionMap revertExternalClasses = new SubstitutionMap() {
@Override
public String get(String key) {
return revertMap.get(key);
}
};
new CssClassRenaming(cssTree.getMutatingVisitController(), revertExternalClasses, null)
.runPass();
return externalClasses;
}
private boolean isStrictResource(JMethod method) {
NotStrict notStrict = method.getAnnotation(NotStrict.class);
return notStrict == null;
}
private List finalizeTree(CssTree cssTree) throws UnableToCompleteException {
new CheckDependencyNodes(cssTree.getMutatingVisitController(), errorManager, false).runPass();
// Don't continue if errors exist
checkErrors();
new CreateStandardAtRuleNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
new CreateMixins(cssTree.getMutatingVisitController(), errorManager).runPass();
new CreateDefinitionNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
new CreateConstantReferences(cssTree.getMutatingVisitController()).runPass();
new CreateConditionalNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
new CreateRuntimeConditionalNodes(cssTree.getMutatingVisitController()).runPass();
new CreateComponentNodes(cssTree.getMutatingVisitController(), errorManager).runPass();
new HandleUnknownAtRuleNodes(cssTree.getMutatingVisitController(), errorManager,
allowedAtRules, true, false).runPass();
new ProcessKeyframes(cssTree.getMutatingVisitController(), errorManager, true, true).runPass();
new ProcessRefiners(cssTree.getMutatingVisitController(), errorManager, true).runPass();
PermutationsCollector permutationsCollector = new PermutationsCollector(cssTree
.getMutatingVisitController(), errorManager);
permutationsCollector.runPass();
return permutationsCollector.getPermutationAxes();
}
private ConstantDefinitions optimizeTree(CssParsingResult cssParsingResult, ResourceContext context,
boolean simplifyCss, boolean eliminateDeadStyles, TreeLogger logger)
throws UnableToCompleteException {
CssTree cssTree = cssParsingResult.tree;
// Collect mixin definitions and replace mixins
CollectMixinDefinitions collectMixinDefinitions = new CollectMixinDefinitions(
cssTree.getMutatingVisitController(), errorManager);
collectMixinDefinitions.runPass();
new ReplaceMixins(cssTree.getMutatingVisitController(), errorManager,
collectMixinDefinitions.getDefinitions()).runPass();
new ProcessComponents