| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 flex2.tools; |
| |
| import flash.css.StyleCondition; |
| import flash.css.StyleDeclaration; |
| import flash.css.StyleDeclarationBlock; |
| import flash.css.StyleProperty; |
| import flash.css.StyleSelector; |
| import flash.swf.tags.DefineFont; |
| import flash.swf.tags.DefineTag; |
| import flash.util.FileUtils; |
| import flash.util.StringJoiner; |
| import flash.util.Trace; |
| import flex2.compiler.config.ServicesDependenciesWrapper; |
| import flex2.compiler.*; |
| import flex2.compiler.abc.AbcClass; |
| import flex2.compiler.as3.binding.ClassInfo; |
| import flex2.compiler.as3.binding.TypeAnalyzer; |
| import flex2.compiler.css.StyleDef; |
| import flex2.compiler.common.CompilerConfiguration; |
| import flex2.compiler.common.Configuration; |
| import flex2.compiler.common.FramesConfiguration; |
| import flex2.compiler.common.MxmlConfiguration; |
| import flex2.compiler.common.RuntimeSharedLibrarySettingsConfiguration; |
| import flex2.compiler.common.Configuration.RslPathInfo; |
| import flex2.compiler.common.FramesConfiguration.FrameInfo; |
| import flex2.compiler.css.StylesContainer; |
| import flex2.compiler.extensions.ExtensionManager; |
| import flex2.compiler.extensions.IPreLinkExtension; |
| import flex2.compiler.i18n.I18nUtils; |
| import flex2.compiler.io.FileUtil; |
| import flex2.compiler.io.TextFile; |
| import flex2.compiler.io.VirtualFile; |
| import flex2.compiler.mxml.lang.StandardDefs; |
| import flex2.compiler.swc.Digest; |
| import flex2.compiler.swc.Swc; |
| import flex2.compiler.swc.SwcScript; |
| import flex2.compiler.util.CompilerMessage; |
| import flex2.compiler.util.MimeMappings; |
| import flex2.compiler.util.Name; |
| import flex2.compiler.util.NameFormatter; |
| import flex2.compiler.util.SwcDependencyUtil; |
| import flex2.compiler.util.NameMappings; |
| import flex2.compiler.util.QName; |
| import flex2.compiler.util.ThreadLocalToolkit; |
| import flex2.compiler.util.VelocityException; |
| import flex2.linker.CULinkable; |
| import flex2.linker.DependencyWalker.LinkState; |
| import flex2.linker.LinkerException; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.*; |
| |
| /** |
| * A flex2.compiler.PreLink implementation, which creates the FlexInit |
| * and SystemManager subclass. |
| */ |
| public class PreLink implements flex2.compiler.PreLink |
| { |
| private final static String DEFAULTS_CSS = "defaults.css"; |
| private final static String DEFAULTS_DASH = "defaults-"; |
| private final static String DOT_CSS = ".css"; |
| |
| public boolean run(List<Source> sources, List<CompilationUnit> units, |
| FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath, ResourceBundlePath bundlePath, |
| ResourceContainer resources, SymbolTable symbolTable, CompilerSwcContext swcContext, |
| NameMappings nameMappings, Configuration configuration) |
| { |
| int initialSourceCount = sources.size(); |
| |
| Set<IPreLinkExtension> extensions = |
| ExtensionManager.getPreLinkExtensions( configuration.getCompilerConfiguration().getExtensionsConfiguration().getExtensionMappings() ); |
| for ( IPreLinkExtension extension : extensions ) |
| { |
| if(ThreadLocalToolkit.errorCount() == 0) { |
| extension.run( sources, units, fileSpec, sourceList, sourcePath, bundlePath, resources, symbolTable, |
| swcContext, configuration ); |
| } |
| } |
| boolean reRunPrelink = processMainUnit(sources, units, resources, symbolTable, nameMappings, configuration); |
| |
| // Check if additional sources were generated after processing the |
| // main compilation unit. The compiler will need to re-run pre-link. |
| if (sources.size() > initialSourceCount || reRunPrelink) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * generate sources for units which require complete set of original units as type context |
| */ |
| public void postRun(List<Source> sources, List<CompilationUnit> units, |
| ResourceContainer resources, |
| SymbolTable symbolTable, |
| CompilerSwcContext swcContext, |
| NameMappings nameMappings, |
| Configuration configuration) |
| { |
| LinkedList<Source> extraSources = new LinkedList<Source>(); |
| LinkedList<String> mixins = new LinkedList<String>(); |
| LinkedList<DefineTag> fonts = new LinkedList<DefineTag>(); |
| Set<String> contributingSwcs = new HashSet<String>(); |
| |
| // Build a set, such as { "core", "controls" }, of the names |
| // of all resource bundles used in all compilation units. |
| // This will be used to set the compiledResourceBundleNames |
| // property of the module factory's info() Object |
| // and the compileResourceBundleNames property |
| // of the _CompileResourceBundleInfo class. |
| processResourceBundleNames(units, configuration); |
| |
| // TODO - factor out the unit iteration / list discovery to a more clear separate step |
| |
| // Autogenerate the _MyApp_FlexInit class. |
| processInitClass(units, configuration, extraSources, mixins, fonts, contributingSwcs, swcContext); |
| |
| // Autogenerate the _MyApp_mx_managers_SystemManager class. |
| boolean generatedLoaderClass = processLoaderClass(units, configuration, extraSources, |
| mixins, fonts, contributingSwcs, |
| swcContext); |
| |
| // Autogenerate the _CompiledResourceBundleInfo class if we didn't autogenerate a loader class. |
| // This enables non-framework apps which simply extend Sprite to use the ResourceManager. |
| if (!generatedLoaderClass) |
| processCompiledResourceBundleInfoClass(units, configuration, extraSources, mixins, fonts, swcContext); |
| |
| // Add the autogenerated sources to the ResourceContainer, so |
| // they can be resolved in subsequent incremental compilations, |
| // where the main unit doesn't require recompilation. |
| for (Source extraSource : extraSources) |
| { |
| sources.add(resources.addResource(extraSource)); |
| } |
| |
| CompilerConfiguration compilerConfiguration = configuration.getCompilerConfiguration(); |
| int compatibilityVersion = compilerConfiguration.getCompatibilityVersion(); |
| |
| StandardDefs standardDefs = ThreadLocalToolkit.getStandardDefs(); |
| TypeAnalyzer typeAnalyzer = symbolTable.getTypeAnalyzer(); |
| assert(typeAnalyzer != null); |
| |
| for (int i = 0, length = units.size(); i < length; i++) |
| { |
| CompilationUnit u = (CompilationUnit) units.get(i); |
| |
| if (u.isRoot()) |
| { |
| StylesContainer stylesContainer = |
| (StylesContainer) symbolTable.getContext().getAttribute(StylesContainer.class.getName()); |
| StylesContainer rootStylesContainer = u.getStylesContainer(); |
| |
| // If the backgroundColor wasn't specified inline, go looking for it in CSS. |
| if ((u.swfMetaData == null) || (u.swfMetaData.getValue("backgroundColor") == null)) |
| { |
| QName qName = u.topLevelDefinitions.last(); |
| |
| if (qName != null) |
| { |
| String def = qName.toString(); |
| lookupBackgroundColor(stylesContainer, rootStylesContainer, u.styleName, |
| NameFormatter.toDot(def), symbolTable, configuration); |
| } |
| } |
| |
| if (rootStylesContainer != null) |
| { |
| // Swap in root's Logger, so warnings get associated correctly. |
| Logger originalLogger = ThreadLocalToolkit.getLogger(); |
| ThreadLocalToolkit.setLogger(u.getSource().getLogger()); |
| rootStylesContainer.validate(symbolTable, nameMappings, u.getStandardDefs(), |
| compilerConfiguration.getThemeNames(), null); |
| ThreadLocalToolkit.setLogger(originalLogger); |
| } |
| |
| Source source = u.getSource(); |
| |
| // Now that we're done validating the StyleContainer, |
| // we can disconnect the root's logger. |
| source.disconnectLogger(); |
| |
| // Clear the root's path resolver, so the |
| // CompilationUnit doesn't hold onto the global path |
| // resolver, which has strong references to things |
| // like the SourcePath, which we want freed up at the |
| // end of a compilation. All the other |
| // CompilationUnit's have their PathResolver cleared |
| // when they reach the ABC state. We hold onto the |
| // root's path resolver until now, because of the |
| // styles |
| source.setPathResolver(null); |
| |
| // C: we don't need the styles container anymore |
| u.setStylesContainer(null); |
| } |
| else if (generatedLoaderClass && !u.getSource().isInternal() && !u.getSource().isSwcScriptOwner()) |
| { |
| // Check if the source is a module or an application. If it is and we know it |
| // is not the root then generate a warning. |
| if (typeAnalyzer != null) |
| { |
| for (QName qName : u.topLevelDefinitions) |
| { |
| ClassInfo info = typeAnalyzer.getClassInfo(qName.toString()); |
| checkForModuleOrApplication(standardDefs, typeAnalyzer, info, qName, configuration); |
| } |
| } |
| } |
| |
| // Only check the dependencies of hand written compilation units. |
| if (!u.getSource().isSwcScriptOwner() && compilerConfiguration.enableSwcVersionFiltering()) |
| { |
| Set<Name> dependencies = new HashSet<Name>(); |
| dependencies.addAll(u.inheritance); |
| dependencies.addAll(u.namespaces); |
| dependencies.addAll(u.expressions); |
| dependencies.addAll(u.types); |
| |
| for (Name name : dependencies) |
| { |
| if (name instanceof QName) |
| { |
| Source dependent = symbolTable.findSourceByQName((QName) name); |
| |
| if (dependent.isSwcScriptOwner()) |
| { |
| SwcScript swcScript = (SwcScript) dependent.getOwner(); |
| Swc swc = swcScript.getLibrary().getSwc(); |
| |
| // Make sure each dependency's minimum |
| // supported version is less than or equal to |
| // the compatibility version. |
| if (compatibilityVersion < swc.getVersions().getMinimumVersion()) |
| { |
| DependencyNotCompatible message = |
| new DependencyNotCompatible(swcScript.getName().replace('/', '.'), |
| swc.getLocation(), |
| swc.getVersions().getMinimumVersionString(), |
| compilerConfiguration.getCompatibilityVersionString()); |
| ThreadLocalToolkit.log(message, u.getSource()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Determine if the class is a module or an application. |
| * |
| * @param standardDefs |
| * @param typeAnalyzer |
| * @param info - ClassInfo of the class being check. |
| * @param root - CompilationUnit of the root, may not be null. |
| * @param qName - qName of the class being checked. |
| * @param configuration |
| */ |
| private void checkForModuleOrApplication(StandardDefs standardDefs, TypeAnalyzer typeAnalyzer, |
| ClassInfo info, QName qName, Configuration configuration) |
| { |
| if (info != null) |
| { |
| // Does the class implement IModule or extend one of the Application classes. |
| if (info.implementsInterface(standardDefs.getModulesPackage(), |
| StandardDefs.INTERFACE_IMODULE_NO_PACKAGE) || |
| info.extendsClass(StandardDefs.CLASS_APPLICATION) || |
| info.extendsClass(StandardDefs.CLASS_SPARK_APPLICATION)) |
| { |
| // Now test that the root does not extend or implement this class before we generate a |
| // warning. |
| ClassInfo rootInfo = typeAnalyzer.getClassInfo(configuration.getMainDefinition()); |
| if (rootInfo != null && |
| !rootInfo.implementsInterface(qName.getNamespace(), qName.getLocalPart()) && |
| !rootInfo.extendsClass(qName.toString())) |
| { |
| ThreadLocalToolkit.getLogger().log(new CompiledAsAComponent(qName.toString(), |
| configuration.getMainDefinition())); |
| } |
| } |
| } |
| |
| } |
| |
| private void locateStyleDefaults(List<CompilationUnit> units, CompilerConfiguration compilerConfiguration) |
| { |
| Set<VirtualFile> defaultsCssFiles = new HashSet<VirtualFile>(); |
| String versionDefaultsCssFileName = null; |
| |
| if (compilerConfiguration.getCompatibilityVersionString() != null) |
| { |
| versionDefaultsCssFileName = DEFAULTS_DASH + compilerConfiguration.getCompatibilityVersionString() + DOT_CSS; |
| } |
| |
| for (int i = 0, length = units.size(); i < length; i++) |
| { |
| CompilationUnit compilationUnit = (CompilationUnit) units.get(i); |
| assert compilationUnit != null : "Must have missed a forcedToStop() check after the most recent batch()"; |
| Source source = compilationUnit.getSource(); |
| |
| if (source.isSwcScriptOwner()) |
| { |
| SwcScript swcScript = (SwcScript) source.getOwner(); |
| Swc swc = swcScript.getLibrary().getSwc(); |
| VirtualFile defaultsCssFile = null; |
| |
| if (versionDefaultsCssFileName != null) |
| { |
| defaultsCssFile = swc.getFile(versionDefaultsCssFileName); |
| } |
| |
| if (defaultsCssFile == null) |
| { |
| defaultsCssFile = swc.getFile(DEFAULTS_CSS); |
| } |
| |
| if (defaultsCssFile != null) |
| { |
| defaultsCssFiles.add(defaultsCssFile); |
| } |
| } |
| } |
| |
| // TODO: figure out how to get these into the correct order |
| compilerConfiguration.addDefaultsCssFiles(defaultsCssFiles); |
| } |
| |
| private boolean processMainUnit(List<Source> sources, List<CompilationUnit> units, ResourceContainer resources, |
| SymbolTable symbolTable, NameMappings nameMappings, Configuration configuration) |
| { |
| boolean generatedSources = false; |
| |
| for (int i = 0, length = units.size(); i < length; i++) |
| { |
| CompilationUnit u = (CompilationUnit) units.get(i); |
| |
| if (u.isRoot()) |
| { |
| swfmetadata(u, configuration); |
| |
| if (u.loaderClass != null) |
| { |
| configuration.setRootClassName(u.loaderClass); |
| } |
| |
| // set the last top level definition as the main definition. Setting the last one allows |
| // for Embed classes at the top of the file |
| QName qName = u.topLevelDefinitions.last(); |
| |
| if (qName != null) |
| { |
| String def = qName.toString(); |
| configuration.setMainDefinition(def); |
| u.getContext().setAttribute("mainDefinition", def); |
| |
| // i.e. isApplication... need loader class for styles. |
| // We also need styles for an AS file that subclasses Application or Module. |
| if (u.loaderClass != null || u.loaderClassBase != null) |
| { |
| CompilerConfiguration compilerConfig = configuration.getCompilerConfiguration(); |
| |
| StylesContainer stylesContainer = |
| (StylesContainer) symbolTable.getContext().getAttribute(StylesContainer.class.getName()); |
| |
| if (stylesContainer == null) |
| { |
| stylesContainer = new StylesContainer(compilerConfig, u, symbolTable.perCompileData); |
| stylesContainer.setNameMappings(nameMappings); |
| symbolTable.getContext().setAttribute(StylesContainer.class.getName(), stylesContainer); |
| } |
| |
| // locate style defaults each time through, |
| // because new dependencies could have brought |
| // in new SWC files with a defaults.css file. |
| List<VirtualFile> cssFiles = compilerConfig.getDefaultsCssFiles(); |
| Set<String> cssFilesSet = new HashSet<String>(); |
| |
| for (VirtualFile cssFile : cssFiles ) |
| { |
| cssFilesSet.add(cssFile.getName()); |
| } |
| |
| locateStyleDefaults(units, compilerConfig); |
| |
| cssFiles = compilerConfig.getDefaultsCssFiles(); |
| Set<String> addedCssFilesSet = null; |
| |
| if (!cssFilesSet.isEmpty()) |
| { |
| Set<String> secondCssFilesSet = new HashSet<String>(); |
| |
| for (VirtualFile cssFile : cssFiles ) |
| { |
| secondCssFilesSet.add(cssFile.getName()); |
| } |
| |
| addedCssFilesSet = new HashSet<String>(); |
| for (String cssName : secondCssFilesSet ) |
| { |
| if (!cssFilesSet.contains(cssName)) |
| { |
| addedCssFilesSet.add(cssName); |
| } |
| } |
| } |
| |
| stylesContainer.loadDefaultStyles(); |
| stylesContainer.validate(symbolTable, nameMappings, u.getStandardDefs(), compilerConfig.getThemeNames(), addedCssFilesSet); |
| |
| List<CULinkable> linkables = new LinkedList<CULinkable>(); |
| |
| for (Iterator it2 = units.iterator(); it2.hasNext();) |
| { |
| linkables.add( new CULinkable( (CompilationUnit) it2.next() ) ); |
| } |
| |
| try |
| { |
| LinkState state = new LinkState(linkables, new HashSet(), configuration.getIncludes(), new HashSet<String>()); |
| |
| // C: generate style classes for components which we want to link in. |
| List<Source> styleSources = new ArrayList<Source>(); |
| generatedSources = stylesContainer.processDependencies(styleSources, state.getDefNames(), resources, |
| u.getSource().getRelativePath().replace('/', '.'), |
| u.getSource().getShortName()); |
| |
| // Sweep through and remove any previous style sources. |
| Iterator<Source> iterator = sources.iterator(); |
| |
| while (iterator.hasNext()) |
| { |
| Source source = iterator.next(); |
| |
| for (Source styleSource : styleSources) |
| { |
| if (source.getName().equals(styleSource.getName())) |
| { |
| iterator.remove(); |
| break; |
| } |
| } |
| } |
| |
| // Now add the new style sources. |
| sources.addAll(styleSources); |
| } |
| catch (LinkerException e) |
| { |
| ThreadLocalToolkit.log( e ); |
| } |
| } |
| } |
| else |
| { |
| ThreadLocalToolkit.log(new NoExternalVisibleDefinition(), u.getSource()); |
| } |
| |
| break; |
| } |
| } |
| |
| return generatedSources; |
| } |
| |
| /** |
| * Looks up the backgroundColor. The first time through, if an |
| * inline styleName from the MXML tag is available, it is used to |
| * lookup a class selector. Otherwise, we look for a styleName in |
| * the local StylesContainer and then the global StylesContainer. |
| * If found, we use it to lookup a class selector. If a class |
| * selector is found, we look for a backgroundColor style |
| * property. If a backgroundColor style property is not found, we |
| * look for a type selector in the local StylesContainer and then |
| * the global StylesContainer. If found, we look for a |
| * backgroundColor style property. If the backgroundColor is |
| * still not found, we recursively call lookupBackgroundColor() |
| * using the super type. If the backgroundColor is still not |
| * found, we look for the backgroundColor in the global selector. |
| */ |
| private static void lookupBackgroundColor(StylesContainer globalStylesContainer, |
| StylesContainer localStylesContainer, |
| String inlineStyleName, |
| String className, |
| SymbolTable symbolTable, |
| Configuration configuration) |
| { |
| assert NameFormatter.toDot(className).equals(className); |
| String styleName = inlineStyleName; |
| |
| if ((styleName == null) && (localStylesContainer != null)) |
| { |
| styleName = lookupStyleName(localStylesContainer, className); |
| } |
| |
| if ((styleName == null) && (globalStylesContainer != null)) |
| { |
| styleName = lookupStyleName(globalStylesContainer, className); |
| } |
| |
| int backgroundColor = -1; |
| |
| if ((styleName != null) && (localStylesContainer != null)) |
| { |
| backgroundColor = lookupClassSelectorBackgroundColor(localStylesContainer, styleName); |
| } |
| |
| if ((backgroundColor == -1) && (styleName != null) && (globalStylesContainer != null)) |
| { |
| backgroundColor = lookupClassSelectorBackgroundColor(globalStylesContainer, styleName); |
| } |
| |
| if ((backgroundColor == -1) && (localStylesContainer != null)) |
| { |
| backgroundColor = lookupTypeSelectorBackgroundColor(localStylesContainer, className); |
| } |
| |
| if ((backgroundColor == -1) && (globalStylesContainer != null)) |
| { |
| backgroundColor = lookupTypeSelectorBackgroundColor(globalStylesContainer, className); |
| } |
| |
| if (backgroundColor == -1) |
| { |
| AbcClass abcClass = symbolTable.getClass(NameFormatter.toColon(className)); |
| |
| if (abcClass != null) |
| { |
| String superTypeName = abcClass.getSuperTypeName(); |
| |
| if (superTypeName != null) |
| { |
| // The styleName is intentionally not passed in, |
| // because we've already tried doing a lookup with it. |
| lookupBackgroundColor(globalStylesContainer, localStylesContainer, null, |
| NameFormatter.toDot(superTypeName), |
| symbolTable, configuration); |
| } |
| else |
| { |
| // A null superTypeName means that we've gone up |
| // the whole inheritance chain, so try the global |
| // selector. |
| if (localStylesContainer != null) |
| { |
| backgroundColor = lookupTypeSelectorBackgroundColor(localStylesContainer, "global"); |
| } |
| |
| if ((backgroundColor == -1) && (globalStylesContainer != null)) |
| { |
| backgroundColor = lookupTypeSelectorBackgroundColor(globalStylesContainer, "global"); |
| } |
| } |
| } |
| } |
| |
| if (backgroundColor != -1) |
| { |
| configuration.setBackgroundColor(backgroundColor); |
| } |
| } |
| |
| /** |
| * Looks for the backgroundColor in a type selector in the |
| * StylesContainer. |
| */ |
| private static int lookupTypeSelectorBackgroundColor(StylesContainer stylesContainer, String className) |
| { |
| int result = -1; |
| StyleDef styleDef = stylesContainer.getStyleDef(className); |
| |
| if (styleDef != null) |
| { |
| Map<String, StyleDeclaration> declarations = styleDef.getDeclarations(); |
| |
| if (declarations != null) |
| { |
| for (StyleDeclaration styleDeclaration : declarations.values()) |
| { |
| Collection<StyleDeclarationBlock> blocks = styleDeclaration.getDeclarationBlocks(); |
| for (StyleDeclarationBlock block : blocks) |
| { |
| StyleProperty styleProperty = block.getProperties().get("backgroundColor"); |
| |
| if (styleProperty != null) |
| { |
| Object value = styleProperty.getValue(); |
| |
| if (value instanceof String) |
| { |
| String backgroundColor = (String) value; |
| |
| try |
| { |
| result = Integer.decode(backgroundColor).intValue(); |
| } |
| catch (NumberFormatException numberFormatException) |
| { |
| ThreadLocalToolkit.log(new InvalidBackgroundColor(backgroundColor), |
| styleDeclaration.getPath(), |
| styleProperty.getLineNumber()); |
| } |
| } |
| // If value is not a String an error will have been reported upstream. |
| } |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Looks for the backgroundColor in a class selector in the |
| * StylesContainer. |
| */ |
| private static int lookupClassSelectorBackgroundColor(StylesContainer stylesContainer, String styleName) |
| { |
| int result = -1; |
| StyleDef styleDef = stylesContainer.getStyleDef("global"); |
| |
| if (styleDef != null) |
| { |
| Map<String, StyleDeclaration> declarations = styleDef.getDeclarations(); |
| |
| if (declarations != null) |
| { |
| for (StyleDeclaration styleDeclaration : declarations.values()) |
| { |
| StyleSelector styleSelector = styleDeclaration.getSelector(); |
| |
| if (styleSelector != null) |
| { |
| List<StyleCondition> conditions = styleSelector.getConditions(); |
| |
| if (conditions != null) |
| { |
| for (StyleCondition styleCondition : conditions) |
| { |
| if ((styleCondition.getKind() == StyleCondition.CLASS_CONDITION) && |
| styleCondition.getValue().equals(styleName)) |
| { |
| Collection<StyleDeclarationBlock> blocks = styleDeclaration.getDeclarationBlocks(); |
| for (StyleDeclarationBlock block : blocks) |
| { |
| StyleProperty styleProperty = block.getProperties().get("backgroundColor"); |
| |
| if (styleProperty != null) |
| { |
| Object value = styleProperty.getValue(); |
| |
| if (value instanceof String) |
| { |
| String backgroundColor = (String) value; |
| |
| try |
| { |
| result = Integer.decode(backgroundColor).intValue(); |
| } |
| catch (NumberFormatException numberFormatException) |
| { |
| ThreadLocalToolkit.log(new InvalidBackgroundColor(backgroundColor), |
| styleDeclaration.getPath(), |
| styleProperty.getLineNumber()); |
| } |
| } |
| // If value is not a String an error will have been reported upstream. |
| } |
| } |
| } |
| // The id attribute is not allowed on the |
| // root tag, so we don't need to handle |
| // StyleCondition.ID_CONDITION here. |
| // Also, StyleCondition.PSEUDO_CONDITION |
| // does not apply, because the root tag |
| // can not be in a state. |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Looks for the styleName in a type selector in the |
| * StylesContainer. |
| */ |
| private static String lookupStyleName(StylesContainer stylesContainer, String className) |
| { |
| String result = null; |
| StyleDef styleDef = stylesContainer.getStyleDef(className); |
| |
| if (styleDef != null) |
| { |
| for (StyleDeclaration styleDeclaration : styleDef.getDeclarations().values()) |
| { |
| Collection<StyleDeclarationBlock> blocks = styleDeclaration.getDeclarationBlocks(); |
| for (StyleDeclarationBlock block : blocks) |
| { |
| StyleProperty styleProperty = block.getProperties().get("styleName"); |
| |
| if (styleProperty != null) |
| { |
| Object value = styleProperty.getValue(); |
| |
| if (value instanceof String) |
| { |
| result = (String) value; |
| } |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private static void swfmetadata(CompilationUnit u, Configuration cfg) |
| { |
| if (u.swfMetaData != null) |
| { |
| String widthString = u.swfMetaData.getValue("width"); |
| if (widthString != null) |
| { |
| cfg.setWidth(widthString); |
| } |
| |
| String heightString = u.swfMetaData.getValue("height"); |
| if (heightString != null) |
| { |
| cfg.setHeight(heightString); |
| } |
| |
| String widthPercent = u.swfMetaData.getValue("widthPercent"); |
| if (widthPercent != null) |
| { |
| cfg.setWidthPercent(widthPercent); |
| } |
| |
| String heightPercent = u.swfMetaData.getValue("heightPercent"); |
| if (heightPercent != null) |
| { |
| cfg.setHeightPercent(heightPercent); |
| } |
| |
| String scriptRecursionLimit = u.swfMetaData.getValue("scriptRecursionLimit"); |
| if (scriptRecursionLimit != null) |
| { |
| try |
| { |
| cfg.setScriptRecursionLimit(Integer.parseInt(scriptRecursionLimit)); |
| } |
| catch (NumberFormatException nfe) |
| { |
| ThreadLocalToolkit.log(new CouldNotParseNumber(scriptRecursionLimit, "scriptRecursionLimit")); |
| } |
| } |
| |
| String scriptTimeLimit = u.swfMetaData.getValue("scriptTimeLimit"); |
| if (scriptTimeLimit != null) |
| { |
| try |
| { |
| cfg.setScriptTimeLimit(Integer.parseInt(scriptTimeLimit)); |
| } |
| catch (NumberFormatException nfe) |
| { |
| ThreadLocalToolkit.log(new CouldNotParseNumber(scriptTimeLimit, "scriptTimeLimit")); |
| } |
| } |
| |
| String frameRate = u.swfMetaData.getValue("frameRate"); |
| if (frameRate != null) |
| { |
| try |
| { |
| cfg.setFrameRate(Integer.parseInt(frameRate)); |
| } |
| catch (NumberFormatException nfe) |
| { |
| ThreadLocalToolkit.log(new CouldNotParseNumber(frameRate, "frameRate")); |
| } |
| } |
| |
| String backgroundColor = u.swfMetaData.getValue("backgroundColor"); |
| if (backgroundColor != null) |
| { |
| try |
| { |
| cfg.setBackgroundColor(Integer.decode(backgroundColor).intValue()); |
| } |
| catch (NumberFormatException numberFormatException) |
| { |
| ThreadLocalToolkit.log(new InvalidBackgroundColor(backgroundColor), u.getSource()); |
| } |
| } |
| |
| String pageTitle = u.swfMetaData.getValue("pageTitle"); |
| if (pageTitle != null) |
| { |
| cfg.setPageTitle(pageTitle); |
| } |
| |
| String useDirectBlit = u.swfMetaData.getValue("useDirectBlit"); |
| if(useDirectBlit != null) |
| { |
| cfg.setUseDirectBlit(Boolean.parseBoolean(useDirectBlit)); |
| } |
| |
| String useGPU = u.swfMetaData.getValue("useGPU"); |
| if(useGPU != null) |
| { |
| cfg.setUseGpu(Boolean.parseBoolean(useGPU)); |
| } |
| |
| // fixme: error on SWF metadata we don't understand |
| } |
| } |
| |
| private SortedSet<String> resourceBundleNames = new TreeSet<String>(); |
| private SortedSet<String> externalResourceBundleNames = new TreeSet<String>(); |
| |
| private void processResourceBundleNames(List units, flex2.compiler.common.Configuration configuration) |
| { |
| Set externs = configuration.getExterns(); |
| |
| for (Iterator it = units.iterator(); it.hasNext();) |
| { |
| CompilationUnit unit = (CompilationUnit) it.next(); |
| if (unit.resourceBundleHistory.size() > 0) |
| { |
| resourceBundleNames.addAll(unit.resourceBundleHistory); |
| |
| if (externs.contains(unit.topLevelDefinitions.first().toString())) |
| { |
| externalResourceBundleNames.addAll(unit.resourceBundleHistory); |
| } |
| } |
| } |
| } |
| |
| private String codegenFlexInit(String flexInitClassName, Set<String> accessibilityList, |
| Map<String, String> remoteClassAliases, Map<String, String> effectTriggers, |
| Set<String> inheritingStyles, Configuration configuration) |
| { |
| StandardDefs standardDefs = ThreadLocalToolkit.getStandardDefs(); |
| CompilerConfiguration compilerConfig = configuration.getCompilerConfiguration(); |
| ServicesDependenciesWrapper servicesDependencies = compilerConfig.getServicesDependencies(); |
| |
| StringBuilder sb = new StringBuilder(); |
| sb.append("package {\n"); |
| sb.append("import flash.display.DisplayObject;\n"); |
| sb.append("import flash.utils.*;\n"); |
| sb.append("import ").append(standardDefs.INTERFACE_IFLEXMODULEFACTORY_DOT).append(";\n"); |
| sb.append("import ").append(standardDefs.INTERFACE_ISTYLEMANAGER2_DOT).append(";\n"); |
| sb.append("import ").append(standardDefs.CLASS_REQUEST_DOT).append(";\n"); |
| sb.append("import ").append(standardDefs.CLASS_STYLEMANAGERIMPL_DOT).append(";\n"); |
| sb.append("import ").append(standardDefs.CLASS_SYSTEMMANAGERCHILDMANAGER_DOT).append(";\n"); |
| sb.append("import ").append(standardDefs.CLASS_TEXTFIELDFACTORY_DOT).append("; TextFieldFactory;\n"); |
| sb.append(codegenAccessibilityImports(accessibilityList)); |
| sb.append(codegenRemoteClassImports( remoteClassAliases )); |
| sb.append(codegenEffectTriggerImports(effectTriggers, standardDefs)); |
| if (servicesDependencies != null) |
| sb.append(servicesDependencies.getImports()); |
| |
| sb.append(codegenResourceBundleMetadata(externalResourceBundleNames)); |
| |
| sb.append("\n[Mixin]\n"); |
| sb.append("public class " + flexInitClassName + "\n"); |
| sb.append("{\n"); |
| sb.append(" public function " + flexInitClassName + "()\n"); |
| sb.append(" {\n"); |
| sb.append(" super();\n"); |
| sb.append(" }\n"); |
| sb.append(" public static function init(fbs:IFlexModuleFactory):void\n"); |
| sb.append(" {\n"); |
| sb.append(" new ChildManager(fbs);\n"); |
| |
| sb.append(" var styleManager:IStyleManager2;\n"); |
| if ((configuration.getCompatibilityVersion() <= flex2.compiler.common.MxmlConfiguration.VERSION_3_0)) |
| { |
| // For backwards compatibility use the top level style manager. |
| sb.append(" styleManager = StyleManagerImpl.getInstance();\n"); |
| sb.append(" fbs.registerImplementation(\"mx.styles::IStyleManager2\", styleManager);\n"); |
| } |
| else if (!configuration.getCompilerConfiguration().getIsolateStyles()) |
| { |
| // If this module factory is not creating its own style factory, then use its parent if available. |
| // Fall back to using the top level style manager. |
| sb.append(" var request:mx.events.Request = new mx.events.Request(mx.events.Request.GET_PARENT_FLEX_MODULE_FACTORY_REQUEST);\n"); |
| sb.append(" DisplayObject(fbs).dispatchEvent(request);\n"); |
| sb.append(" var moduleFactory:IFlexModuleFactory = request.value as IFlexModuleFactory;\n"); |
| sb.append(" if (moduleFactory)\n"); |
| sb.append(" styleManager = IStyleManager2(moduleFactory.getImplementation(\"mx.styles::IStyleManager2\"));\n\n"); |
| sb.append(" if (!styleManager)\n"); |
| sb.append(" styleManager = StyleManagerImpl.getInstance();\n"); |
| sb.append(" fbs.registerImplementation(\"mx.styles::IStyleManager2\", styleManager);\n"); |
| } |
| else |
| { |
| sb.append(" styleManager = new StyleManagerImpl(fbs);\n"); |
| } |
| |
| sb.append(codegenQualifiedTypeSelectors(configuration)); |
| sb.append(codegenEffectTriggerRegistration(effectTriggers)); |
| sb.append(codegenAccessibilityList(accessibilityList)); |
| sb.append(codegenRemoteClassAliases(remoteClassAliases, flexInitClassName, configuration)); |
| sb.append(codegenInheritingStyleRegistration(inheritingStyles)); |
| if (servicesDependencies != null) |
| sb.append(servicesDependencies.getServerConfigXmlInit()); |
| sb.append(" }\n"); |
| if (servicesDependencies != null) |
| sb.append(servicesDependencies.getReferences()); |
| |
| sb.append("} // FlexInit\n"); |
| sb.append("} // package\n"); |
| |
| return sb.toString(); |
| } |
| |
| private void processInitClass(List units, Configuration configuration, |
| List<Source> extraSources, LinkedList<String> mixins, |
| LinkedList<DefineTag> fonts, |
| Set<String> contributingSwcs, |
| CompilerSwcContext swcContext) |
| { |
| Set<String> accessibilityList = null; |
| Map<String, String> remoteClassAliases = new TreeMap<String, String>() |
| { |
| private static final long serialVersionUID = -8015004853369794727L; |
| |
| /** |
| * Override so warning messages can be logged. |
| */ |
| public String put(String key, String value) |
| { |
| // check for duplicate values and log a warning if any remote |
| // classes try to use the same alias. |
| if (containsValue(value)) |
| { |
| Object existingKey = null; |
| for (Iterator iter = entrySet().iterator(); iter.hasNext();) |
| { |
| Map.Entry entry = (Map.Entry)iter.next(); |
| if (value != null && value.equals(entry.getValue())) |
| { |
| existingKey = entry.getKey(); |
| break; |
| } |
| } |
| ThreadLocalToolkit.log(new ClassesMappedToSameRemoteAlias((String)key, (String)existingKey, (String)value)); |
| } |
| return super.put(key, value); |
| } |
| |
| }; |
| |
| Map<String, String> effectTriggers = new TreeMap<String, String>(); |
| Set<String> inheritingStyles = new HashSet<String>(); |
| CompilationUnit mainUnit = null; |
| Set externs = swcContext.getExterns(); |
| boolean removeUnusedRSLs = configuration.getRemoveUnusedRsls(); |
| |
| for (int i = 0, size = units.size(); i < size; i++) |
| { |
| CompilationUnit u = (CompilationUnit) units.get(i); |
| |
| if (u.isRoot()) |
| { |
| mainUnit = u; |
| } |
| |
| if (u.hasAssets()) |
| { |
| List<DefineFont> fontList = u.getAssets().getFonts(); |
| |
| // don't add font assets for definitions that have been externed. |
| if (fontList != null && !fontList.isEmpty() && |
| !isCompilationUnitExternal(u, externs) && |
| !u.getSource().isInternal()) |
| { |
| fonts.addAll(fontList); // save for later... |
| } |
| } |
| |
| remoteClassAliases.putAll( u.remoteClassAliases ); |
| |
| effectTriggers.putAll( u.effectTriggers ); |
| mixins.addAll( u.mixins ); |
| |
| inheritingStyles.addAll( u.styles.getInheritingStyles() ); |
| |
| if (configuration.getCompilerConfiguration().accessible()) |
| { |
| Set<String> unitAccessibilityList = u.getAccessibilityClasses(); |
| if (unitAccessibilityList != null) |
| { |
| if (accessibilityList == null) |
| { |
| accessibilityList = new HashSet<String>(); |
| } |
| accessibilityList.addAll(unitAccessibilityList); |
| } |
| } |
| |
| if (removeUnusedRSLs) |
| { |
| // Record which swcs have contributed the scripts. We will use |
| // this later to figure out which RSLs to load. |
| Source source = u.getSource(); |
| |
| if (!source.isInternal() && source.isSwcScriptOwner()) |
| { |
| SwcScript script = (SwcScript)source.getOwner(); |
| contributingSwcs.add(script.getSwcLocation()); |
| } |
| } |
| } |
| |
| String flexInitClass = null; |
| if (mainUnit != null) |
| { |
| for (Iterator it = mainUnit.extraClasses.iterator(); it.hasNext();) |
| { |
| String extraClass = (String) it.next(); |
| // FIXME - Depending on the contents of the classname is not the solution we want. |
| if (extraClass.indexOf("FlexInit") != -1) |
| { |
| flexInitClass = extraClass; |
| break; |
| } |
| } |
| } |
| |
| if (flexInitClass != null) |
| { |
| String code = codegenFlexInit(flexInitClass, accessibilityList, remoteClassAliases, |
| effectTriggers, inheritingStyles, configuration); |
| String name = flexInitClass + "-generated.as"; |
| |
| if (configuration.getCompilerConfiguration().keepGeneratedActionScript()) |
| { |
| saveGenerated(name, code, configuration.getCompilerConfiguration().getGeneratedDirectory()); |
| } |
| |
| Source s = new Source(new TextFile(code, name, null, MimeMappings.getMimeType(name)), "", flexInitClass, null, false, false, false); |
| // C: It doesn't look like this Source needs any path resolution. null is fine... |
| s.setPathResolver(null); |
| extraSources.add(s); |
| mixins.addFirst( flexInitClass ); // we already iterated, lets put this one at the head in any case |
| } |
| |
| } |
| |
| /** |
| * |
| * @param unit compilation unit, may not be null |
| * @param externs - list of externs, may not be null |
| * @return true if the compilation unit, u, has any definitions that are in the list of |
| * interns. |
| */ |
| public static boolean isCompilationUnitExternal(CompilationUnit unit, Set externs) |
| { |
| for (int i = 0, size = unit == null ? 0 : unit.topLevelDefinitions.size(); i < size; i++) |
| { |
| if (externs.contains(unit.topLevelDefinitions.get(i).toString())) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| private boolean processLoaderClass(List units, |
| Configuration configuration, |
| List<Source> sources, |
| List<String> mixins, |
| List<DefineTag> fonts, |
| Set<String> contributingSwcs, |
| CompilerSwcContext swcContext) |
| { |
| if (!configuration.generateFrameLoader) |
| { |
| return false; |
| } |
| |
| LinkedList<FrameInfo> frames = new LinkedList<FrameInfo>(); |
| frames.addAll( configuration.getFrameList() ); |
| |
| CompilationUnit mainUnit = null; |
| for (Iterator it = units.iterator(); it.hasNext();) |
| { |
| CompilationUnit unit = (CompilationUnit) it.next(); |
| if (unit.isRoot()) |
| { |
| mainUnit = unit; |
| break; |
| } |
| } |
| |
| if (mainUnit == null) |
| { |
| return false; |
| } |
| |
| // If we built the main unit from source on this pass, we will have saved |
| // off information that will help us determine whether we need to generate |
| // an IFlexModuleFactory derivative. |
| // |
| // IMPORTANT: Having frame metadata is NOT the indicator! We only generate |
| // a system manager in sync with compiling a MXML application from source; |
| // otherwise, the generated class is assumed to already exist! |
| |
| String generateLoaderClass = null; |
| String baseLoaderClass = null; |
| String windowClass = null; |
| //String preloaderClass = null; |
| Map<String, Object> rootAttributes = null; |
| Map<String, Object> rootAttributeEmbedVars = null; |
| Map<String, Object> rootAttributeEmbedNames = null; |
| //boolean usePreloader = false; |
| List<RslPathInfo> cdRsls = configuration.getRslPathInfo(); |
| List<String> rsls = configuration.getRuntimeSharedLibraries(); |
| String[] locales = configuration.getCompilerConfiguration().getLocales(); |
| |
| // ALGORITHM: |
| // Generate a loader class iff all the below are true: |
| // 1a. We compiled MXML on this compilation run. |
| // or |
| // 1b. We were not MXML but the base class does know a loader. |
| // 2. We found Frame loaderClass metadata in a superclass |
| // 3. We did not find Frame loaderClass metadata in the app |
| |
| |
| |
| if ((mainUnit.loaderClass != null) && (mainUnit.auxGenerateInfo != null)) |
| { |
| generateLoaderClass = (String) mainUnit.auxGenerateInfo.get("generateLoaderClass"); |
| baseLoaderClass = (String) mainUnit.auxGenerateInfo.get("baseLoaderClass"); |
| windowClass = (String) mainUnit.auxGenerateInfo.get("windowClass"); |
| //preloaderClass = (String) mainUnit.auxGenerateInfo.get("preloaderClass"); |
| //Boolean b = (Boolean) mainUnit.auxGenerateInfo.get("usePreloader"); |
| |
| @SuppressWarnings("unchecked") |
| Map<String, Object> tmpRootAttributes = (Map<String, Object>) mainUnit.auxGenerateInfo.get("rootAttributes"); |
| rootAttributes = tmpRootAttributes; |
| @SuppressWarnings("unchecked") |
| Map<String, Object> tmpRootAttributeEmbedVars = (Map<String, Object>) mainUnit.auxGenerateInfo.get("rootAttributeEmbedVars"); |
| rootAttributeEmbedVars = tmpRootAttributeEmbedVars; |
| @SuppressWarnings("unchecked") |
| Map<String, Object> tmpRootAttributeEmbedNames = (Map<String, Object>) mainUnit.auxGenerateInfo.get("rootAttributeEmbedNames"); |
| rootAttributeEmbedNames = tmpRootAttributeEmbedNames; |
| |
| // mainUnit.auxGenerateInfo = null; // All done, thanks! |
| |
| assert generateLoaderClass != null; |
| |
| //usePreloader = ((b == null) || b.booleanValue()); |
| |
| //assert usePreloader || (preloaderClass != null); |
| |
| // Is there any way we can eliminate having default class here? |
| // Seems like this should be in SystemManager, not the compiler. |
| |
| //if (usePreloader && (preloaderClass == null)) // |
| //{ |
| // preloaderClass = "mx.preloaders.DownloadProgressBar"; |
| //} |
| } |
| else if ((mainUnit.loaderClass == null) && (mainUnit.loaderClassBase != null)) |
| { |
| // AS project, but the base class knows of a loader. |
| baseLoaderClass = mainUnit.loaderClassBase; |
| windowClass = mainUnit.topLevelDefinitions.last().toString(); |
| generateLoaderClass = (windowClass + "_" + mainUnit.loaderClassBase).replaceAll("[^A-Za-z0-9]", "_"); |
| |
| mainUnit.loaderClass = generateLoaderClass; |
| } |
| else if ((mainUnit.loaderClass == null) && |
| ((rsls.size() > 0) || (cdRsls.size() > 0))) |
| { |
| ThreadLocalToolkit.log(new MissingFactoryClassInFrameMetadata(), mainUnit.getSource()); |
| return false; |
| } |
| else |
| { |
| return false; |
| } |
| |
| String generatedLoaderCode = codegenModuleFactory(baseLoaderClass.replace(':', '.'), |
| generateLoaderClass.replace(':', '.'), |
| windowClass.replace(':', '.'), |
| rootAttributes, |
| rootAttributeEmbedVars, |
| rootAttributeEmbedNames, |
| cdRsls, |
| rsls, |
| mixins, |
| fonts, |
| frames, |
| locales, |
| resourceBundleNames, |
| externalResourceBundleNames, |
| configuration, |
| contributingSwcs, |
| swcContext, |
| false); |
| |
| String generatedLoaderFile = generateLoaderClass + ".as"; |
| |
| TextFile genSource = new TextFile(generatedLoaderCode, |
| generatedLoaderFile, |
| mainUnit.getSource().getParent(), |
| MimeMappings.AS); |
| |
| Source s = new Source(genSource, mainUnit.getSource(), generateLoaderClass, false, false); |
| sources.add(s); |
| |
| if (configuration.getCompilerConfiguration().keepGeneratedActionScript()) |
| { |
| saveGenerated(generatedLoaderFile, generatedLoaderCode, configuration.getCompilerConfiguration().getGeneratedDirectory()); |
| } |
| |
| return true; |
| } |
| |
| |
| private String codegenAccessibilityImports(Set<String> accessibilityImplementations) |
| { |
| StringBuilder sb = new StringBuilder(); |
| |
| sb.append("import flash.system.*\n"); |
| if (accessibilityImplementations != null) |
| { |
| for (Iterator<String> it = accessibilityImplementations.iterator(); it.hasNext();) |
| { |
| sb.append("import " + it.next() + ";\n"); |
| } |
| } |
| |
| return sb.toString(); |
| } |
| |
| // TODO save to alt location instead of mangling name, to keep code compilable under OPD |
| // TODO make sure code generators obey OPD in name <-> code |
| public static void saveGenerated(String name, String code, String dir) |
| { |
| final String suffix = "-generated.as"; |
| final String as3ext = ".as"; |
| if (!name.endsWith(suffix) && name.endsWith(as3ext)) |
| { |
| name = name.substring(0, name.length() - as3ext.length()) + suffix; |
| } |
| |
| name = FileUtils.addPathComponents( dir, name, File.separatorChar ); |
| |
| try |
| { |
| FileUtil.writeFile(name, code); |
| } |
| catch (IOException e) |
| { |
| ThreadLocalToolkit.log(new VelocityException.UnableToWriteGeneratedFile(name, e.getLocalizedMessage())); |
| } |
| } |
| |
| |
| /** |
| * Codegen the cdRsls and placeholderRsls arrays. |
| * |
| * @param cdRsls List of cross-domain rsls in the configuration. |
| * @param requiredRsls true if we are writing out required rsls (cdRsls). |
| * @param unusedRsls set of RSL that are not used by the application. |
| * @param configuration |
| * @param swcContext |
| * @return |
| */ |
| private static String codegenCdRslList(List<RslPathInfo> cdRsls, |
| boolean requiredRsls, |
| Set<String> unusedRsls, |
| Configuration configuration, |
| CompilerSwcContext swcContext) |
| { |
| |
| // ignore -rslp option if -static-rsls is set |
| if (configuration.getStaticLinkRsl()) { |
| return "[]"; |
| } |
| |
| StringBuilder buf = new StringBuilder(); |
| buf.append("[\n"); |
| int i = 0; // keep track of rsl index; |
| for (Iterator<Configuration.RslPathInfo> iter = cdRsls.iterator(); iter.hasNext(); i++) |
| { |
| Configuration.RslPathInfo info = (Configuration.RslPathInfo)iter.next(); |
| |
| // skip if the associated swc is filtered from our context. |
| if (swcContext.getSwc(info.getSwcVirtualFile().getName()) == null) |
| continue; |
| |
| String swcPath = info.getSwcVirtualFile().getName(); |
| |
| // Write out either the required rsls (to cdRsls) or the |
| // unused rsls (to placeholderRsls). |
| if (requiredRsls && unusedRsls.contains(swcPath) || |
| !requiredRsls && !unusedRsls.contains(swcPath)) |
| continue; |
| |
| // output message about rsl urls. |
| if (requiredRsls) |
| { |
| List<String>rslUrls = info.getRslUrls(); |
| |
| switch (rslUrls.size()) |
| { |
| case 0: |
| assert false; // One RSL URL is required. |
| break; |
| case 1: |
| ThreadLocalToolkit.log(new RequiredRslUrl(rslUrls.get(0))); |
| break; |
| case 2: |
| ThreadLocalToolkit.log(new RequiredRslUrlWithFailover(rslUrls.get(0))); |
| break; |
| default: |
| ThreadLocalToolkit.log(new RequiredRslUrlWithMultipleFailovers( |
| rslUrls.get(0), |
| rslUrls.size() - 1)); |
| break; |
| } |
| } |
| |
| // Write out the rsl info and fail over info into an array of rsl objects. |
| buf.append("["); |
| codegenRslInfoObject(swcContext, configuration, info, unusedRsls, buf); |
| buf.append("]"); |
| |
| if (iter.hasNext()) |
| buf.append(",\n"); |
| } |
| |
| // end of all rsls |
| buf.append("]\n"); |
| |
| return buf.toString(); |
| } |
| |
| |
| /** |
| * Figure out which rsls we can remove. The tricky part is we may need to load |
| * an unused rsl because a downstream rsl has inheritance dependencies on it. |
| * |
| * @param cdRsls |
| * @param contributingSwcs |
| * @param configuration |
| * @param swcContext |
| * @return Set of Strings where each string is the location of a swc file. |
| */ |
| private static Set<String> calculateUnusedRsls(List<RslPathInfo> cdRsls, |
| Set<String> contributingSwcs, |
| Configuration configuration, |
| CompilerSwcContext swcContext) |
| { |
| if (!configuration.getRemoveUnusedRsls()) |
| { |
| return Collections.emptySet(); |
| } |
| |
| Set<String> forceRsls = configuration. |
| getRuntimeSharedLibrarySettingsConfiguration(). |
| getForceRslsPaths(); |
| |
| List<String> unusedRsls = new LinkedList<String>(); // running list of unused rsls |
| Set<String>downstreamRsls = new HashSet<String>(); // loaded rsls downstream from first unused rsl |
| boolean addDownstreamRsl = false; |
| |
| // Get unused RSLs and verify that there are no downstream RSLs that have |
| // and inheritance dependency on them. |
| for (RslPathInfo info : cdRsls) |
| { |
| // skip if the associated swc is filtered from our context. |
| if (swcContext.getSwc(info.getSwcVirtualFile().getName()) == null) |
| continue; |
| |
| // skip loading the RSL if it does not contribute any classes to |
| // the application and it is not forced. |
| String swcPath = info.getSwcVirtualFile().getName(); |
| if (!contributingSwcs.contains(swcPath) && |
| !forceRsls.contains(swcPath)) |
| { |
| unusedRsls.add(info.getSwcVirtualFile().getName()); |
| addDownstreamRsl = true; |
| } |
| else if (addDownstreamRsl) |
| { |
| downstreamRsls.add(swcPath); |
| } |
| } |
| |
| if (unusedRsls.size() == 0) |
| { |
| return Collections.emptySet(); |
| } |
| |
| Set<String> requiredInheritanceRsls = SwcDependencyUtil. |
| checkInheritanceDependencies(unusedRsls, |
| downstreamRsls, |
| swcContext); |
| if (!requiredInheritanceRsls.isEmpty()) |
| unusedRsls.removeAll(requiredInheritanceRsls); |
| |
| return new HashSet<String>(unusedRsls); |
| } |
| |
| /** |
| * Append a rsl info to the cross-domain startup info. |
| * This is all the properties of the primary rsl and |
| * its fail overs. |
| * |
| * @param swcContext |
| * @param info cross-domain rsl info |
| * @param index chooses the rsl info from the primary rsl and fail overs. |
| * @param buf StringBuilder to append info to |
| */ |
| private static void codegenRslInfoObject(CompilerSwcContext swcContext, |
| Configuration configuration, |
| Configuration.RslPathInfo info, |
| Set<String> unusedRsls, |
| StringBuilder buf) { |
| List<String>rslUrls = info.getRslUrls(); |
| RuntimeSharedLibrarySettingsConfiguration rslSettingsConfig = |
| configuration.getRuntimeSharedLibrarySettingsConfiguration(); |
| |
| for (int i = 0; i < rslUrls.size(); i++) |
| { |
| // start new object |
| buf.append("new RSLData("); |
| String url = rslUrls.get(i); |
| buf.append("\"" + url + "\",\n"); |
| |
| // write policy url |
| buf.append("\"" + |
| info.getPolicyFileUrls().get(i) + |
| "\",\n"); |
| |
| // get the swc for current rsl |
| String swcPath = info.getSwcVirtualFile().getName(); |
| Swc swc = swcContext.getSwc(swcPath); |
| |
| // write digest for each rsl in the list |
| boolean secureRsls = configuration.getVerifyDigests(); |
| Boolean isSigned = (Boolean)info.getSignedFlags().get(i); |
| Digest digest = swc.getDigest(Swc.LIBRARY_SWF, |
| Digest.SHA_256, |
| isSigned.booleanValue()); |
| |
| if (digest == null || !digest.hasDigest()) |
| { |
| // if the digest is not available then throw an exception, |
| // "No digest found in catalog.xml. Either compile the application with |
| // the -verify-digests=false or compile the library with |
| // -create-digest=true" |
| if (isSigned.booleanValue()) { |
| ThreadLocalToolkit.log(new MissingSignedLibraryDigest(swc.getLocation())); |
| } |
| else { |
| ThreadLocalToolkit.log(new MissingUnsignedLibraryDigest(swc.getLocation())); |
| } |
| return; |
| } |
| |
| buf.append("\"" + digest.getValue() + "\",\n"); |
| buf.append("\"" + digest.getType() + "\","); |
| buf.append(info.getSignedFlags().get(i) + ","); |
| buf.append(secureRsls + ","); |
| buf.append("\"" + rslSettingsConfig.getApplicationDomain(swcPath) + "\""); |
| |
| // end of one object in the array |
| buf.append(")"); |
| |
| if (i + 1 < rslUrls.size()) |
| buf.append(",\n"); |
| } |
| } |
| |
| |
| private static String codegenRslList(List<String> rsls) |
| { |
| if ((rsls != null) && (rsls.size() > 0)) |
| { |
| StringBuilder rb = new StringBuilder(); |
| |
| rb.append("["); |
| for (Iterator<String> it = rsls.iterator(); it.hasNext();) |
| { |
| String rslUrl = (String)it.next(); |
| |
| ThreadLocalToolkit.log(new RequiredRslUrl(rslUrl)); |
| |
| rb.append("{url: \"" + rslUrl + "\", size: -1}"); |
| if (it.hasNext()) |
| { |
| rb.append(", "); |
| } |
| } |
| rb.append("]\n"); |
| |
| return rb.toString(); |
| } |
| return "[]"; |
| } |
| |
| private static String codegenMixinList(List<String> mixins) |
| { |
| assert mixins != null && mixins.size() > 0; |
| StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemQuoter(); |
| return "[ " + StringJoiner.join(mixins, ", ", itemStringer) + " ]"; |
| } |
| |
| private static String codegenFrameClassList(List<FrameInfo> frames) |
| { |
| assert frames != null && frames.size() > 0; |
| StringBuilder mb = new StringBuilder(); |
| mb.append("{"); |
| |
| for (Iterator<FrameInfo> it = frames.iterator(); it.hasNext();) |
| { |
| FramesConfiguration.FrameInfo frameInfo = it.next(); |
| mb.append("\""); |
| mb.append(frameInfo.label); |
| mb.append("\":\""); |
| mb.append(frameInfo.frameClasses.get(0)); |
| mb.append("\""); |
| if (it.hasNext()) |
| { |
| mb.append(", "); |
| } |
| } |
| mb.append("}\n"); |
| return mb.toString(); |
| } |
| |
| |
| |
| private static String codegenFontList(List<DefineTag> fonts) |
| { |
| if ((fonts == null) || (fonts.size() == 0)) |
| { |
| return ""; |
| } |
| |
| class FontInfo |
| { |
| boolean plain; |
| boolean bold; |
| boolean italic; |
| boolean bolditalic; |
| } |
| |
| Map<String, FontInfo> fontMap = new TreeMap<String, FontInfo>(); |
| for (Iterator<DefineTag> it = fonts.iterator(); it.hasNext();) |
| { |
| DefineFont font = (DefineFont) it.next(); |
| FontInfo fi = fontMap.get( font.getFontName() ); |
| if (fi == null) |
| { |
| fi = new FontInfo(); |
| fontMap.put( font.getFontName(), fi ); |
| } |
| |
| fi.plain |= (!font.isBold() && !font.isItalic()); |
| fi.bolditalic |= (font.isBold() && font.isItalic()); |
| fi.bold |= font.isBold(); |
| fi.italic |= font.isItalic(); |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| |
| sb.append(" {\n"); |
| |
| for (Iterator it = fontMap.entrySet().iterator(); it.hasNext();) |
| { |
| Map.Entry e = (Map.Entry) it.next(); |
| String fontName = (String) e.getKey(); |
| FontInfo fontInfo = (FontInfo) e.getValue(); |
| |
| sb.append("\"" + fontName + "\" : {" + |
| "regular:" + (fontInfo.plain? "true":"false") + |
| ", bold:" + (fontInfo.bold? "true":"false") + |
| ", italic:" + (fontInfo.italic? "true":"false") + |
| ", boldItalic:" + (fontInfo.bolditalic? "true":"false") + "}\n"); |
| if (it.hasNext()) |
| { |
| sb.append(",\n"); |
| } |
| } |
| sb.append("}\n"); |
| |
| return sb.toString(); |
| } |
| |
| private String codegenAccessibilityList(Set<String> accessibilityImplementations) |
| { |
| if ((accessibilityImplementations == null) || (accessibilityImplementations.size() == 0)) |
| { |
| return ""; |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| |
| if ((accessibilityImplementations != null) && (accessibilityImplementations.size() != 0)) |
| { |
| sb.append(" // trace(\"Flex accessibility startup: \" + Capabilities.hasAccessibility);\n"); |
| sb.append(" if (Capabilities.hasAccessibility) {\n"); |
| for (Iterator<String> it = accessibilityImplementations.iterator(); it.hasNext();) |
| { |
| sb.append(" " + it.next() + ".enableAccessibility();\n"); |
| } |
| sb.append(" }\n"); |
| } |
| |
| if (Trace.accessible) |
| { |
| Trace.trace("codegenAccessibilityList"); |
| if (sb.length() > 0) |
| { |
| Trace.trace(sb.toString()); |
| } |
| else |
| { |
| Trace.trace("empty"); |
| } |
| } |
| |
| return sb.toString(); |
| } |
| |
| private String codegenRemoteClassImports( Map<String, String> remoteClassAliases ) |
| { |
| StringBuilder sb = new StringBuilder(); |
| |
| if (remoteClassAliases.size() > 0) |
| { |
| sb.append( "import flash.net.registerClassAlias;\nimport flash.net.getClassByAlias;\n" ); |
| sb.append( "import mx.managers.SystemManagerGlobals;\n"); |
| sb.append( "import mx.resources.ResourceManager;\n"); |
| } |
| |
| for (Iterator<String> it = remoteClassAliases.keySet().iterator(); it.hasNext(); ) |
| { |
| String className = it.next(); |
| sb.append( "import " + className + ";\n" ); |
| } |
| return sb.toString(); |
| |
| } |
| private String codegenRemoteClassAliases( Map<String, String> remoteClassAliases, |
| String initClassName, |
| Configuration configuration) |
| { |
| StringBuilder sb = new StringBuilder(); |
| |
| for (Map.Entry<String, String> e : remoteClassAliases.entrySet()) |
| { |
| String className = (String) e.getKey(); |
| String alias = (String) e.getValue(); |
| sb.append( " // " + className + "\n"); |
| sb.append( " try \n"); |
| sb.append( " { \n"); |
| sb.append( " if (flash.net.getClassByAlias(\"" + alias + "\") != " + className + ") \n"); |
| sb.append( " { \n"); |
| sb.append( " flash.net.registerClassAlias(\"" + alias + "\", " + className + "); \n"); |
| // Only generate the diagnostic code if compiling for debug. |
| if (configuration.debug()) |
| { |
| sb.append( " if (fbs != SystemManagerGlobals.topLevelSystemManagers[0]) \n"); |
| sb.append( " { \n"); |
| sb.append( " trace(ResourceManager.getInstance().getString( \"core\", \n"); |
| sb.append( " \"remoteClassMemoryLeak\",\n"); |
| sb.append( " [\"" + className + "\",\"" + |
| configuration.getMainDefinition() + "\",\"" + |
| initClassName + "\"]));\n"); |
| sb.append( " } \n"); |
| } |
| sb.append( " } \n"); |
| sb.append( " } \n"); |
| sb.append( " catch (e:Error) \n"); |
| sb.append( " { \n"); |
| sb.append( " flash.net.registerClassAlias(\"" + alias + "\", " + className + "); \n"); |
| // Only generate the diagnostic code if compiling for debug. |
| if (configuration.debug()) |
| { |
| sb.append( " if (fbs != SystemManagerGlobals.topLevelSystemManagers[0]) \n"); |
| sb.append( " { \n"); |
| sb.append( " trace(ResourceManager.getInstance().getString( \"core\", \n"); |
| sb.append( " \"remoteClassMemoryLeak\",\n"); |
| sb.append( " [\"" + className + "\",\"" + |
| configuration.getMainDefinition() + "\",\"" + |
| initClassName + "\"]));\n"); |
| sb.append( " } \n"); |
| } |
| sb.append( " } \n\n"); |
| } |
| return sb.toString(); |
| } |
| |
| private String codegenEffectTriggerImports(Map<String, String> effectTriggers, StandardDefs standardDefs) |
| { |
| if (effectTriggers.size() > 0) |
| { |
| return "import " + standardDefs.CLASS_EFFECTMANAGER_DOT + ";\n" + "import " + standardDefs.NAMESPACE_MX_INTERNAL_DOT + ";\n"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| |
| private String codegenEffectTriggerRegistration( Map<String, String> effectTriggers ) |
| { |
| StringBuilder sb = new StringBuilder(); |
| |
| for (Iterator it = effectTriggers.entrySet().iterator(); it.hasNext(); ) |
| { |
| Map.Entry e = (Map.Entry) it.next(); |
| String name = (String) e.getKey(); |
| String event = (String) e.getValue(); |
| |
| sb.append( " EffectManager.mx_internal::registerEffectTrigger(\"" + name + "\", \"" + event + "\");\n"); |
| } |
| |
| return sb.toString(); |
| } |
| |
| private String codegenInheritingStyleRegistration( Set<String> inheritingStyles ) |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(" var styleNames:Array = ["); |
| |
| Iterator<String> iterator = inheritingStyles.iterator(); |
| |
| while ( iterator.hasNext() ) |
| { |
| String styleName = iterator.next(); |
| sb.append("\"" + styleName + "\""); |
| if ( iterator.hasNext() ) |
| { |
| sb.append(", "); |
| } |
| } |
| |
| StandardDefs standardDefs = ThreadLocalToolkit.getStandardDefs(); |
| |
| sb.append("];\n\n"); |
| sb.append(" for (var i:int = 0; i < styleNames.length; i++)\n"); |
| sb.append(" {\n"); |
| sb.append(" styleManager.registerInheritingStyle(styleNames[i]);\n"); |
| sb.append(" }\n"); |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns a string like |
| * [ "en_US", "ja_JP" ] |
| */ |
| private static String codegenCompiledLocales( String[] locales ) |
| { |
| StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemQuoter(); |
| return "[ " + StringJoiner.join(locales, ", ", itemStringer) + " ]"; |
| } |
| |
| /** |
| * Returns a string like |
| * [ "core", "controls", "MyApp" ] |
| */ |
| private static String codegenCompiledResourceBundleNames( SortedSet<String> bundleNames ) |
| { |
| StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemQuoter(); |
| return "[ " + StringJoiner.join(bundleNames, ", ", itemStringer) + " ]"; |
| } |
| |
| private static String codegenCompatibilityCall(Configuration configuration) |
| { |
| String compatibilityCall; |
| String compatibilityVersionString = configuration.getCompatibilityVersionString(); |
| |
| if (configuration.getCompatibilityVersion() == MxmlConfiguration.CURRENT_VERSION || |
| compatibilityVersionString == null) |
| { |
| compatibilityCall = ""; |
| } |
| else |
| { |
| compatibilityCall = " FlexVersion.compatibilityVersionString = \"" + compatibilityVersionString + "\";"; |
| } |
| return compatibilityCall; |
| } |
| |
| private static String codegenQualifiedTypeSelectors(Configuration configuration) |
| { |
| // If we're not using qualified type selectors, change the runtime default to false. |
| boolean qualified = configuration.getQualifiedTypeSelectors(); |
| return qualified ? "" : " styleManager.qualifiedTypeSelectors = false;\n"; |
| } |
| |
| static String codegenModuleFactory(String base, |
| String rootClassName, |
| String topLevelWindowClass, |
| Map<String, Object> rootAttributes, |
| Map<String, Object> rootAttributeEmbedVars, |
| Map<String, Object> rootAttributeEmbedNames, |
| List<RslPathInfo> cdRsls, |
| List<String> rsls, |
| List<String> mixins, |
| List<DefineTag> fonts, |
| List<FrameInfo> frames, |
| String[] locales, |
| SortedSet<String> resourceBundleNames, |
| SortedSet<String> externalResourceBundleNames, |
| Configuration configuration, |
| Set<String> contributingSwcs, |
| CompilerSwcContext swcContext, |
| boolean isLibraryCompile) |
| { |
| String lineSep = System.getProperty("line.separator"); |
| boolean hasFonts = (fonts == null ? false : fonts.size() > 0); |
| StandardDefs standardDefs = ThreadLocalToolkit.getStandardDefs(); |
| |
| String[] codePieces = new String[] |
| { |
| "package", lineSep, |
| "{", lineSep, lineSep, |
| codegenImports(base, rootAttributes, rootAttributeEmbedVars, fonts, configuration, standardDefs, isLibraryCompile, hasFonts), |
| codegenResourceBundleMetadata(null /*externalResourceBundleNames*/), |
| "[ExcludeClass]", lineSep, |
| "public class ", rootClassName, lineSep, |
| " extends ", base, lineSep, |
| " implements IFlexModuleFactory, ISWFContext", lineSep, |
| "{", lineSep, |
| codegenLinkInCrossDomainRSLItem(configuration, lineSep, cdRsls, standardDefs), |
| " public function ", rootClassName, "()", lineSep, |
| " {", lineSep, |
| codegenCompatibilityCall(configuration), lineSep, |
| " super();", lineSep, |
| codegenAddRslCompleteListener(isLibraryCompile, hasFonts, lineSep), |
| " }", lineSep, lineSep, |
| /** |
| * Calls a function in the modules context. Needed for |
| * ElementFormat.getFontMetrics so we'll generalize in case |
| * we find a need to do this for some other method. |
| */ |
| !isLibraryCompile ? |
| " override " : "", |
| " public function callInContext(fn:Function, thisArg:Object, argArray:Array, returns:Boolean=true):*", lineSep, |
| " {", lineSep, |
| " if (returns)", lineSep, |
| " return fn.apply(thisArg, argArray);", lineSep, |
| " else", lineSep, |
| " fn.apply(thisArg, argArray);", lineSep, |
| " }", lineSep, lineSep, |
| codegenAddPreloadedRSLStub(isLibraryCompile, lineSep), |
| codegenGetRegisterImplementationStubs(isLibraryCompile, lineSep), |
| !isLibraryCompile ? |
| " override " : "", |
| " public function create(... params):Object", lineSep, |
| " {", lineSep, |
| codegenCreateApply(isLibraryCompile, lineSep), |
| codegenGetMainClassName(topLevelWindowClass, configuration, lineSep), |
| " var mainClass:Class = Class(getDefinitionByName(mainClassName));", lineSep, |
| " if (!mainClass)", lineSep, |
| " return null;", lineSep, lineSep, |
| " var instance:Object = new mainClass();", lineSep, |
| " if (instance is IFlexModule)", lineSep, |
| " (IFlexModule(instance)).moduleFactory = this;", lineSep, |
| codegenRegisterEmbeddedFonts(fonts, lineSep), |
| " return instance;", lineSep, |
| " }", lineSep, lineSep, |
| codegenEmbeddedApplicaitonAttributes(rootAttributeEmbedVars), |
| " /**", lineSep, |
| " * @private", lineSep, |
| " */", lineSep, |
| " private var _info:Object;", lineSep, lineSep, |
| !isLibraryCompile ? |
| " override" : "", |
| " public function info():Object", lineSep, |
| " {", lineSep, |
| " if (!_info)", lineSep, |
| " {", lineSep, |
| " _info = {", lineSep, |
| codegenInfo(topLevelWindowClass, rootAttributes, rootAttributeEmbedNames, cdRsls, rsls, mixins, fonts, |
| frames, locales, resourceBundleNames, configuration, |
| contributingSwcs, swcContext), |
| " }", lineSep, |
| " }", lineSep, |
| " return _info;", lineSep, |
| " }", lineSep, lineSep, |
| codegenRSLSecurityWrapper(isLibraryCompile, lineSep), lineSep, |
| codegenModuleFactorySecurityWrapper(isLibraryCompile, hasFonts, lineSep), lineSep, |
| codegenRslCompleteListener(isLibraryCompile, hasFonts, lineSep), |
| "}", lineSep, lineSep, |
| "}", lineSep, |
| }; |
| |
| return StringJoiner.join(codePieces, null); |
| } |
| |
| |
| private static String codegenLinkInCrossDomainRSLItem( |
| Configuration configuration, String lineSep, |
| List cdRsls, StandardDefs standardDefs) |
| { |
| if (cdRsls == null || cdRsls.isEmpty()) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| " // Cause the CrossDomainRSLItem class to be linked into this application.", lineSep, |
| " import ", standardDefs.CLASS_CROSSDOMAINRSLITEM_DOT, "; CrossDomainRSLItem;", lineSep, lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| private static String codegenImportEmbeddedFontRegistry(List<DefineTag> fonts, |
| String lineSep, StandardDefs standardDefs) |
| { |
| if (fonts == null || fonts.size() == 0) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| "import ", standardDefs.CLASS_EMBEDDEDFONTREGISTRY_DOT, ";", lineSep, |
| "import ", standardDefs.CLASS_SINGLETON_DOT, ";", lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| |
| private static String codegenRegisterEmbeddedFonts(List<DefineTag> fonts, String lineSep) |
| { |
| if (fonts == null || fonts.size() == 0) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| " if (params.length == 0) {", lineSep, |
| " Singleton.registerClass(\"mx.core::IEmbeddedFontRegistry\",", lineSep, |
| " Class(getDefinitionByName(\"mx.core::EmbeddedFontRegistry\")));", lineSep, |
| " EmbeddedFontRegistry.registerFonts(info()[\"fonts\"], this);", lineSep, |
| "}" |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| private static String codegenCreateApply(boolean isLibraryCompile, String lineSep) |
| { |
| if (isLibraryCompile) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| " if (params.length > 0 && !(params[0] is String))", lineSep, |
| " return super.create.apply(this, params);", lineSep, lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| private static String codegenGetMainClassName(String topLevelWindowClass, Configuration configuration, String lineSep) |
| { |
| String[] code = { |
| topLevelWindowClass == null ? |
| " var mainClassName:String = String(params[0])" : |
| " var mainClassName:String = params.length == 0 ? \"", |
| topLevelWindowClass == null ? "" : topLevelWindowClass, |
| topLevelWindowClass == null ? "" : "\" : String(params[0]);", lineSep, |
| }; |
| return StringJoiner.join(code, null); |
| |
| |
| } |
| |
| private static String codegenResourceBundleMetadata(SortedSet<String> resourceBundleNames) |
| { |
| if (resourceBundleNames == null) |
| { |
| return ""; |
| } |
| String lineSep = System.getProperty("line.separator"); |
| |
| StringBuilder codePieces = new StringBuilder(); |
| for (Iterator<String> i = resourceBundleNames.iterator(); i.hasNext(); ) |
| { |
| codePieces.append("[ResourceBundle(\"" + i.next() + "\")]" + lineSep); |
| } |
| |
| return codePieces.toString(); |
| } |
| |
| |
| private static String codegenImports(String base, Map<String, Object> rootAttributes, |
| Map<String, Object> rootAttributeEmbedVars, List<DefineTag> fonts, |
| Configuration configuration, StandardDefs standardDefs, |
| boolean isLibraryCompile, boolean hasFonts) |
| { |
| String lineSep = System.getProperty("line.separator"); |
| |
| StringBuilder sb = new StringBuilder(512); |
| sb.append(codegenEventImport(isLibraryCompile, hasFonts, lineSep)); |
| sb.append("import flash.display.LoaderInfo;").append(lineSep); |
| sb.append("import flash.text.Font;").append(lineSep); |
| sb.append("import flash.text.TextFormat;").append(lineSep); |
| sb.append("import flash.text.engine.TextBlock;").append(lineSep); |
| sb.append("import flash.text.engine.TextLine;").append(lineSep); |
| sb.append("import flash.system.ApplicationDomain;").append(lineSep); |
| sb.append("import flash.system.Security").append(lineSep); |
| sb.append("import flash.utils.Dictionary;").append(lineSep); |
| sb.append("import flash.utils.getDefinitionByName;").append(lineSep); |
| sb.append("import flashx.textLayout.compose.ISWFContext;").append(lineSep); |
| sb.append("import ").append(standardDefs.INTERFACE_IFLEXMODULE_DOT).append(";").append(lineSep); |
| sb.append("import ").append(standardDefs.INTERFACE_IFLEXMODULEFACTORY_DOT).append(";").append(lineSep); |
| sb.append(codegenImportEmbeddedFontRegistry(fonts, lineSep, standardDefs)); |
| sb.append("import mx.core.RSLData;").append(lineSep); |
| sb.append("import mx.events.RSLEvent;").append(lineSep); |
| |
| if (configuration.getCompatibilityVersionString() != null) |
| { |
| sb.append("import ").append(standardDefs.CLASS_FLEXVERSION_DOT).append(";").append(lineSep); |
| } |
| |
| // If we're not using qualified type selectors, change the runtime default to false. |
| if (!configuration.getQualifiedTypeSelectors()) |
| { |
| sb.append("import ").append(standardDefs.CLASS_STYLEMANAGER_DOT).append(";").append(lineSep); |
| sb.append("import ").append(standardDefs.NAMESPACE_MX_INTERNAL_DOT).append(";").append(lineSep); |
| } |
| |
| sb.append("import ").append(base).append(";").append(lineSep); |
| |
| // Import runtimeDPIProvider class if it exists. |
| String runtimeDPIProviderClass = getRuntimeDPIProviderClass(rootAttributes, configuration); |
| if (runtimeDPIProviderClass != null) |
| { |
| sb.append("import ").append(runtimeDPIProviderClass).append(";").append(lineSep); |
| } |
| |
| // TODO - eliminate any special handling of preloaderDisplayClass! |
| String preloader = getPreloaderClass(rootAttributes, configuration); |
| if (preloader != null) |
| { |
| sb.append("import ").append(preloader).append(";").append(lineSep); |
| } |
| |
| // If the splashScreenImage was specified as a Class and not @Embed, we need to import it here |
| if (rootAttributes != null && rootAttributes.containsKey("splashScreenImage") && |
| (rootAttributeEmbedVars == null || !rootAttributeEmbedVars.containsKey("splashScreenImage"))) |
| { |
| String splashImageClass = (String) rootAttributes.get("splashScreenImage"); |
| sb.append("import ").append(splashImageClass).append(";").append(lineSep); |
| } |
| |
| sb.append(lineSep); |
| |
| return sb.toString(); |
| } |
| |
| private static String getRuntimeDPIProviderClass(Map<String, Object> rootAttributes, Configuration configuration) |
| { |
| // Is dpiMapping attribute defined on the root tag? |
| if (rootAttributes != null && rootAttributes.containsKey("runtimeDPIProvider")) |
| return (String)rootAttributes.get("runtimeDPIProvider"); |
| |
| return null; |
| } |
| |
| private static String getPreloaderClass(Map<String, Object> rootAttributes, Configuration configuration) |
| { |
| // Is preloader attribute defined on the root tag? |
| if (rootAttributes != null && rootAttributes.containsKey("preloader")) |
| return (String)rootAttributes.get("preloader"); |
| |
| // Is preloader specified in the compiler arguments? |
| String preloader = configuration.getCompilerConfiguration().getPreloader(); |
| if (preloader != null) |
| { |
| preloader = preloader.trim(); |
| return preloader.length() == 0 ? null : preloader; |
| } |
| |
| int version = configuration.getCompatibilityVersion(); |
| if (version < MxmlConfiguration.VERSION_4_0) |
| return "mx.preloaders.DownloadProgressBar"; |
| else |
| return "mx.preloaders.SparkDownloadProgressBar"; |
| } |
| |
| /** |
| * Add mx.events.Event import to support RSL event handler. |
| * Only needed when compiling a SWC. |
| * |
| * @param isLibraryCompile |
| * @param hasFonts |
| * @param lineSep |
| * @return |
| */ |
| private static String codegenEventImport(boolean isLibraryCompile, |
| boolean hasFonts, String lineSep) |
| { |
| if (!(isLibraryCompile && hasFonts)) |
| { |
| return ""; |
| } |
| |
| String[] eventImport = {"import flash.events.Event", lineSep,}; |
| return StringJoiner.join(eventImport, null); |
| |
| } |
| |
| private static String codegenEmbeddedApplicaitonAttributes(Map<String, Object> rootAttributeEmbedVars) |
| { |
| if (rootAttributeEmbedVars == null || rootAttributeEmbedVars.size() == 0) |
| return ""; |
| |
| String lineSep = System.getProperty("line.separator"); |
| return StringJoiner.join(rootAttributeEmbedVars.values(), lineSep) + lineSep; |
| } |
| |
| private static String codegenInfo(String topLevelWindowClass, |
| Map<String, Object> rootAttributes, |
| Map<String, Object> rootAttributeEmbedNames, |
| List<RslPathInfo> cdRsls, |
| List<String> rsls, |
| List<String> mixins, |
| List<DefineTag> fonts, |
| List<FrameInfo> frames, |
| String[] locales, |
| SortedSet<String> resourceBundleNames, |
| Configuration configuration, |
| Set<String> contributingSwcs, |
| CompilerSwcContext swcContext) |
| { |
| // Build a map of the name/value pairs for the info |
| TreeMap<String, Object> t = new TreeMap<String, Object>(); |
| |
| t.put("currentDomain", "ApplicationDomain.currentDomain"); |
| |
| if (topLevelWindowClass != null) |
| { |
| t.put("mainClassName", "\"" + topLevelWindowClass + "\""); |
| } |
| |
| if (rootAttributes != null) |
| { |
| for (Iterator<Map.Entry<String, Object>> it = rootAttributes.entrySet().iterator(); it.hasNext(); ) |
| { |
| Map.Entry<String, Object> e = it.next(); |
| |
| // TODO - eliminate any special handling of preloaderDisplayClass! |
| if ("preloader".equals(e.getKey())) |
| { |
| // skip, will handle preloader after the loop |
| } |
| else if ("usePreloader".equals(e.getKey())) |
| { |
| t.put(e.getKey(), e.getValue()); |
| } |
| else if ("runtimeDPIProvider".equals(e.getKey())) |
| { |
| // skip, will handle runtimeDPIProvider after the loop |
| } |
| else if ("implements".equals(e.getKey())) |
| { |
| // skip |
| } |
| else if ("backgroundColor".equals(e.getKey())) |
| { |
| t.put(e.getKey(), "\"0x" + Integer.toHexString(configuration.backgroundColor()).toUpperCase() + "\""); |
| } |
| else |
| { |
| String embedName = null; |
| if (rootAttributeEmbedNames != null) |
| embedName = (String) rootAttributeEmbedNames.get(e.getKey()); |
| |
| if (embedName != null) |
| t.put(e.getKey(), embedName); |
| else if ("splashScreenImage".equals(e.getKey())) |
| t.put(e.getKey(), e.getValue()); // SplashScreenImage is a special attribute of type Class. |
| else |
| t.put(e.getKey(), "\"" + e.getValue() + "\""); |
| } |
| } |
| |
| String preloader = getPreloaderClass(rootAttributes, configuration); |
| if (preloader != null) |
| { |
| // we use the actual class in order to get a link dependency |
| t.put("preloader", preloader); |
| } |
| |
| String runtimeDPIProvider = getRuntimeDPIProviderClass(rootAttributes, configuration); |
| if (runtimeDPIProvider != null) |
| { |
| t.put("runtimeDPIProvider", runtimeDPIProvider); |
| } |
| } |
| |
| boolean hasCdRsls = (cdRsls != null) && (cdRsls.size() > 0); |
| boolean hasRsls = (rsls != null) && (rsls.size() > 0); |
| |
| if (hasCdRsls || hasRsls) |
| ThreadLocalToolkit.log(new RequiredRsls()); //log "Required RSLs:" message |
| |
| if (hasCdRsls) |
| { |
| // The required RSLs are put in "cdRsls", the others are put in "placeholderRsls". |
| // get the rsls that we can remove. |
| Set<String> unusedRsls = calculateUnusedRsls(cdRsls, contributingSwcs, |
| configuration, swcContext); |
| |
| t.put("cdRsls", codegenCdRslList(cdRsls, true, unusedRsls, configuration, swcContext)); |
| t.put("placeholderRsls", codegenCdRslList(cdRsls, false, unusedRsls, configuration, swcContext)); |
| } |
| |
| if (hasRsls) |
| t.put("rsls", codegenRslList(rsls)); |
| |
| if ((mixins != null) && (mixins.size() > 0)) |
| t.put("mixins", codegenMixinList(mixins)); |
| |
| if ((fonts != null) && (fonts.size() > 0)) |
| t.put("fonts", codegenFontList(fonts) ); |
| |
| if ((frames != null) && (frames.size() > 0)) |
| t.put("frames", codegenFrameClassList(frames)); |
| |
| if (locales != null) |
| t.put("compiledLocales", codegenCompiledLocales(locales)); |
| |
| if ((resourceBundleNames != null) && (resourceBundleNames.size() > 0)) |
| t.put("compiledResourceBundleNames", codegenCompiledResourceBundleNames(resourceBundleNames)); |
| |
| // Codegen a string from that map. |
| String lineSep = System.getProperty("line.separator"); |
| StringJoiner.ItemStringer itemStringer = new StringJoiner.MapEntryItemWithColon(); |
| return " " + |
| StringJoiner.join(t.entrySet(), "," + lineSep + " ", itemStringer) + |
| lineSep; |
| } |
| |
| /** |
| * Add an RSL complete listener to this RSL. |
| * |
| * @param isLibraryCompile true if we are compiling the library.swf for a swc. |
| * @param lineSep |
| * @return ActionScript code to add an RSL complete listener. If we are not compiling |
| * the library.swf(RSL) of a SWC then no code is added. |
| */ |
| private static String codegenAddRslCompleteListener(boolean isLibraryCompile, boolean hasFonts, |
| String lineSep) { |
| |
| if (!(isLibraryCompile && hasFonts)) |
| { |
| return ""; |
| } |
| |
| String[] addCompleteListenerCall = { |
| " this.root.loaderInfo.addEventListener(Event.COMPLETE, RSLRootCompleteListener);", |
| lineSep }; |
| return StringJoiner.join(addCompleteListenerCall, null); |
| } |
| |
| |
| /** |
| * Add an RSL complete listener handler to this RSL. |
| * |
| * @param isLibraryCompile true if we are compiling the library.swf for a swc. |
| * @param lineSep |
| * @return ActionScript code to add an RSL complete listener. If we are not compiling |
| * the library.swf(RSL) of a SWC then no code is added. |
| */ |
| private static String codegenRslCompleteListener(boolean isLibraryCompile, boolean hasFonts, |
| String lineSep) |
| { |
| if (!(isLibraryCompile && hasFonts)) |
| { |
| return ""; |
| } |
| |
| String[] completeListener = { |
| " private function RSLRootCompleteListener(event:Event):void", lineSep, |
| " {", lineSep, |
| " EmbeddedFontRegistry.registerFonts(info()[\"fonts\"], this)", lineSep, |
| " this.root.removeEventListener(Event.COMPLETE, RSLRootCompleteListener);", lineSep, |
| " }", lineSep, }; |
| |
| return StringJoiner.join(completeListener, null); |
| } |
| |
| /** |
| * Implement the allowDomain() and allowInsecureDomain() of the IFlexModuleFactory interface. |
| * This code is only generated for compiled applications and modules, not for RSLs code in a SWC. |
| * |
| * @param isLibraryCompile true if we are compiling the library.swf for a swc. |
| * @param lineSep |
| * @return |
| */ |
| private static String codegenModuleFactorySecurityWrapper(boolean isLibraryCompile, boolean hasFonts, |
| String lineSep) |
| { |
| if (isLibraryCompile && !hasFonts) |
| { |
| return ""; |
| } |
| |
| if (isLibraryCompile) |
| return codegenModuleFactorySecurityWrapperStubs(lineSep); |
| |
| String[] code = { |
| " /**", lineSep, |
| " * @private", lineSep, |
| " */", lineSep, |
| " private var _preloadedRSLs:Dictionary; // key: LoaderInfo, value: Vector.<RSLData>", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " */", lineSep, |
| " private var _allowDomainParameters:Vector.<Array>;", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " */", lineSep, |
| " private var _allowInsecureDomainParameters:Vector.<Array>;", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * The RSLs loaded by this system manager before the application", lineSep, |
| " * starts. RSLs loaded by the application are not included in this list.", lineSep, |
| " */", lineSep, |
| " override public function get preloadedRSLs():Dictionary", lineSep, |
| " {", lineSep, |
| " if (_preloadedRSLs == null)", lineSep, |
| " _preloadedRSLs = new Dictionary(true);", lineSep, |
| " return _preloadedRSLs;", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Calls Security.allowDomain() for the SWF associated with this IFlexModuleFactory", lineSep, |
| " * plus all the SWFs assocatiated with RSLs preLoaded by this IFlexModuleFactory.", lineSep, |
| " *", lineSep, |
| " */", lineSep, |
| " override public function allowDomain(... domains):void", lineSep, |
| " {", lineSep, |
| " Security.allowDomain.apply(null, domains);", lineSep, lineSep, |
| " for (var loaderInfo:Object in _preloadedRSLs)", lineSep, |
| " {", lineSep, |
| " if (loaderInfo.content && (\"allowDomainInRSL\" in loaderInfo.content))", lineSep, |
| " loaderInfo.content[\"allowDomainInRSL\"].apply(null, domains);", lineSep, |
| " }", lineSep, lineSep, |
| " if (!_allowDomainParameters)", lineSep, |
| " _allowDomainParameters = new Vector.<Array>();", lineSep, |
| " _allowDomainParameters.push(domains);", lineSep, lineSep, |
| " // Run our handler before the default handlers so the RSL is trusted before the", lineSep, |
| " // default handlers run.", lineSep, |
| " addEventListener(RSLEvent.RSL_ADD_PRELOADED, addPreloadedRSLHandler, false, 50);", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Calls Security.allowInsecureDomain() for the SWF associated with this IFlexModuleFactory", lineSep, |
| " * plus all the SWFs assocatiated with RSLs preLoaded by this IFlexModuleFactory.", lineSep, |
| " *", lineSep, |
| " */", lineSep, |
| " override public function allowInsecureDomain(... domains):void", lineSep, |
| " {", lineSep, |
| " Security.allowInsecureDomain.apply(null, domains);", lineSep, lineSep, |
| " for (var loaderInfo:Object in _preloadedRSLs)", lineSep, |
| " {", lineSep, |
| " if (loaderInfo.content && (\"allowInsecureDomainInRSL\" in loaderInfo.content))", lineSep, |
| " loaderInfo.content[\"allowInsecureDomainInRSL\"].apply(null, domains);", lineSep, |
| " }", lineSep, |
| " if (!_allowInsecureDomainParameters)", lineSep, |
| " _allowInsecureDomainParameters = new Vector.<Array>();", lineSep, |
| " _allowInsecureDomainParameters.push(domains);", lineSep, lineSep, |
| " // Run our handler before the default handlers so the RSL is trusted before the", lineSep, |
| " // default handlers run.", lineSep, |
| " addEventListener(RSLEvent.RSL_ADD_PRELOADED, addPreloadedRSLHandler, false, 50);", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " */", lineSep, |
| " private function addPreloadedRSLHandler(event:RSLEvent):void", lineSep, |
| " {", lineSep, |
| " var loaderInfo:LoaderInfo = event.loaderInfo;", lineSep, |
| " if (!loaderInfo || !loaderInfo.content)", lineSep, |
| " return;", lineSep, |
| " var domains:Array", lineSep, |
| " if (allowDomainsInNewRSLs && _allowDomainParameters)", lineSep, |
| " {", lineSep, |
| " for each (domains in _allowDomainParameters)", lineSep, |
| " {", lineSep, |
| " if (\"allowDomainInRSL\" in loaderInfo.content)", lineSep, |
| " loaderInfo.content[\"allowDomainInRSL\"].apply(null, domains);", lineSep, |
| " }", lineSep, |
| " }", lineSep, lineSep, |
| " if (allowInsecureDomainsInNewRSLs && _allowInsecureDomainParameters)", lineSep, |
| " {", lineSep, |
| " for each (domains in _allowInsecureDomainParameters)", lineSep, |
| " {", lineSep, |
| " if (\"allowInsecureDomainInRSL\" in loaderInfo.content)", lineSep, |
| " loaderInfo.content[\"allowInsecureDomainInRSL\"].apply(null, domains);", lineSep, |
| " }", lineSep, |
| " }", lineSep, |
| " }", lineSep, lineSep, |
| |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| /** |
| * Generate stubs for the security wrappers of the IFlexModuleFactory interface. |
| * This code is only generated for RSLs code in a SWC has contains fonts. |
| * |
| * @param lineSep |
| * @return |
| */ |
| private static String codegenModuleFactorySecurityWrapperStubs(String lineSep) |
| { |
| String[] stubs = { |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function get allowDomainsInNewRSLs():Boolean", lineSep, |
| " {", lineSep, |
| " return false;", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function set allowDomainsInNewRSLs(value:Boolean):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function get allowInsecureDomainsInNewRSLs():Boolean", lineSep, |
| " {", lineSep, |
| " return false;", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function set allowInsecureDomainsInNewRSLs(value:Boolean):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function get preloadedRSLs():Dictionary", lineSep, |
| " {", lineSep, |
| " return null;", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function allowDomain(... domains):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " *", lineSep, |
| " */", lineSep, |
| " public function allowInsecureDomain(... domains):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| }; |
| |
| return StringJoiner.join(stubs, null); |
| } |
| |
| /** |
| * Generate flash player Security wrapper calls. |
| * |
| * @param lineSep |
| * @return |
| */ |
| static String codegenRSLSecurityWrapper(boolean isLibraryCompile, String lineSep) |
| { |
| if (!isLibraryCompile) |
| return ""; |
| |
| String[] code = { |
| " /*", lineSep, |
| " * Calls Security.allowDomain() for the SWF associated with this RSL", lineSep, |
| " * @param a list of domains to trust. This parameter is passed to Security.allowDomain().", lineSep, |
| " */", lineSep, |
| " public function allowDomainInRSL(... domains):void", lineSep, |
| " {", lineSep, |
| " Security.allowDomain.apply(null, domains);", lineSep, |
| " }", lineSep, lineSep, |
| " /*", lineSep, |
| " * Calls Security.allowInsecureDomain() for the SWF associated with this RSL", lineSep, |
| " * @param a list of domains to trust. This parameter is passed to Security.allowInsecureDomain().", lineSep, |
| " */", lineSep, |
| " public function allowInsecureDomainInRSL(... domains):void", lineSep, |
| " {", lineSep, |
| " Security.allowInsecureDomain.apply(null, domains);", lineSep, |
| " }", lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| /** |
| * Generate stubs for getImplementation() and registerImplemenation() if we are |
| * compiling a module factory for a SWC, instead of a SWF file. For a SWF file |
| * use don't override the implementation. |
| * |
| * @param isLibraryCompile true if we are compiling the library.swf for a swc. |
| * @param lineSep |
| * @return |
| */ |
| private static String codegenGetRegisterImplementationStubs(boolean isLibraryCompile, |
| String lineSep) |
| { |
| if (!isLibraryCompile) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function getImplementation(interfaceName:String):Object", lineSep, |
| " {", lineSep, |
| " return null;", lineSep, |
| " }", lineSep, lineSep, |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function registerImplementation(interfaceName:String,", lineSep, |
| " impl:Object):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| /** |
| * Generate stubs for addPreloadedRSL()if we are |
| * compiling a module factory for a SWC, instead of a SWF file. For a SWF file |
| * use don't override the implementation. |
| * |
| * @param isLibraryCompile true if we are compiling the library.swf for a swc. |
| * @param lineSep |
| * @return |
| */ |
| private static String codegenAddPreloadedRSLStub(boolean isLibraryCompile, |
| String lineSep) |
| { |
| if (!isLibraryCompile) |
| { |
| return ""; |
| } |
| |
| String[] code = { |
| " /**", lineSep, |
| " * @private", lineSep, |
| " * Stub for RSL", lineSep, |
| " */", lineSep, |
| " public function addPreloadedRSL(loaderInfo:LoaderInfo, rsl:Vector.<RSLData>):void", lineSep, |
| " {", lineSep, |
| " }", lineSep, lineSep, |
| }; |
| |
| return StringJoiner.join(code, null); |
| } |
| |
| private void processCompiledResourceBundleInfoClass(List units, |
| Configuration configuration, |
| List<Source> sources, |
| List<String> mixins, |
| List<DefineTag> fonts, |
| CompilerSwcContext swcContext) |
| { |
| CompilerConfiguration config = configuration.getCompilerConfiguration(); |
| |
| // Don't add the _CompiledResourceBundleInfo class |
| // if we are compiling in Flex 2 compatibility mode, |
| // or if there are no locales, |
| // or if there are no resource bundle names. |
| |
| int version = config.getCompatibilityVersion(); |
| if (version < MxmlConfiguration.VERSION_3_0) |
| { |
| return; |
| } |
| |
| String[] locales = config.getLocales(); |
| if (locales.length == 0) |
| { |
| return; |
| } |
| |
| if (resourceBundleNames.size() == 0) |
| { |
| return; |
| } |
| |
| String className = I18nUtils.COMPILED_RESOURCE_BUNDLE_INFO; |
| String code = I18nUtils.codegenCompiledResourceBundleInfo(locales, resourceBundleNames); |
| |
| String generatedFileName = className + "-generated.as"; |
| if (config.keepGeneratedActionScript()) |
| { |
| saveGenerated(generatedFileName, code, config.getGeneratedDirectory()); |
| } |
| |
| Source s = new Source(new TextFile(code, generatedFileName, null, |
| MimeMappings.getMimeType(generatedFileName)), |
| "", className, null, false, false, false); |
| s.setPathResolver(null); |
| sources.add(s); |
| |
| // Ensure that this class gets linked in, |
| // because no other code depends on it. |
| // (ResourceManager looks it up by name.) |
| configuration.getIncludes().add(className); |
| } |
| |
| // error messages |
| |
| public static class DependencyNotCompatible extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = -917715346261180364L; |
| |
| public String definition; |
| public String swc; |
| public String swcMinimumVersion; |
| public String compatibilityVersion; |
| |
| public DependencyNotCompatible(String definition, String swc, |
| String swcMinimumVersion, String compatibilityVersion) |
| { |
| this.definition = definition; |
| this.swc = swc; |
| this.swcMinimumVersion = swcMinimumVersion; |
| this.compatibilityVersion = compatibilityVersion; |
| } |
| } |
| |
| public static class NoExternalVisibleDefinition extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = -917715346261180363L; |
| |
| public NoExternalVisibleDefinition() |
| { |
| super(); |
| } |
| } |
| |
| public static class MissingFactoryClassInFrameMetadata extends CompilerMessage.CompilerWarning |
| { |
| private static final long serialVersionUID = 1064989348731483344L; |
| |
| public MissingFactoryClassInFrameMetadata() |
| { |
| super(); |
| } |
| } |
| |
| public static class InvalidBackgroundColor extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = -623864938378435687L; |
| |
| public String backgroundColor; |
| |
| public InvalidBackgroundColor(String backgroundColor) |
| { |
| super(); |
| this.backgroundColor = backgroundColor; |
| } |
| } |
| |
| public static class CouldNotParseNumber extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = 2186380089141871093L; |
| |
| public CouldNotParseNumber(String num, String attribute) |
| { |
| this.num = num; |
| this.attribute = attribute; |
| } |
| |
| public String num; |
| public String attribute; |
| } |
| |
| public static class MissingSignedLibraryDigest extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = -1865860949469218550L; |
| |
| public MissingSignedLibraryDigest(String libraryPath) |
| { |
| this.libraryPath = libraryPath; |
| } |
| |
| public String libraryPath; |
| } |
| |
| public static class MissingUnsignedLibraryDigest extends CompilerMessage.CompilerError |
| { |
| private static final long serialVersionUID = 8092666584208136222L; |
| |
| public MissingUnsignedLibraryDigest(String libraryPath) |
| { |
| this.libraryPath = libraryPath; |
| } |
| |
| public String libraryPath; |
| } |
| |
| /** |
| * Warn users with [RemoteClass] metadata that ends up mapping more than one class to the same alias. |
| */ |
| public static class ClassesMappedToSameRemoteAlias extends CompilerMessage.CompilerWarning |
| { |
| private static final long serialVersionUID = 4365280637418299961L; |
| |
| public ClassesMappedToSameRemoteAlias(String className, String existingClassName, String alias) |
| { |
| this.className = className; |
| this.existingClassName = existingClassName; |
| this.alias = alias; |
| } |
| |
| public String className; |
| public String existingClassName; |
| public String alias; |
| } |
| |
| /** |
| * Tell the user they are making a mistake by compiling a module or application as a component. |
| */ |
| public static class CompiledAsAComponent extends CompilerMessage.CompilerWarning |
| { |
| private static final long serialVersionUID = -2874508107726441350L; |
| |
| public CompiledAsAComponent(String className, String mainDefinition) |
| { |
| this.className = className; |
| this.mainDefinition = mainDefinition; |
| } |
| |
| public String className; |
| public String mainDefinition; |
| |
| } |
| |
| /** |
| * "Required RSLs:" message. |
| */ |
| public static class RequiredRsls extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = 2303666861783668660L; |
| |
| public RequiredRsls() |
| { |
| } |
| |
| } |
| |
| /** |
| * Display RSL URL with no failovers. |
| */ |
| public static class RequiredRslUrl extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = 2303666861783668660L; |
| |
| public RequiredRslUrl(String rslUrl) |
| { |
| this.rslUrl = rslUrl; |
| } |
| |
| public String rslUrl; |
| } |
| |
| /** |
| * Display RSL URL with one failover. |
| */ |
| public static class RequiredRslUrlWithFailover extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = 2303666861783668660L; |
| |
| public RequiredRslUrlWithFailover(String rslUrl) |
| { |
| this.rslUrl = rslUrl; |
| } |
| |
| public String rslUrl; |
| } |
| |
| /** |
| * Display RSL URL with more than one failovers. |
| */ |
| public static class RequiredRslUrlWithMultipleFailovers extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = 2303666861783668660L; |
| |
| public RequiredRslUrlWithMultipleFailovers(String rslUrl, int failoverCount) |
| { |
| this.rslUrl = rslUrl; |
| this.failoverCount = failoverCount; |
| } |
| |
| public String rslUrl; |
| public int failoverCount; |
| |
| } |
| |
| } |