Package org.apache.flex.compiler.internal.targets

Source Code of org.apache.flex.compiler.internal.targets.SWFTarget$FramesInformation

/*
*
*  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 org.apache.flex.compiler.internal.targets;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.flex.abc.ABCLinker;
import org.apache.flex.compiler.config.RSLSettings;
import org.apache.flex.compiler.constants.IASLanguageConstants;
import org.apache.flex.compiler.constants.IMetaAttributeConstants;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.definitions.references.IResolvedQualifiersReference;
import org.apache.flex.compiler.definitions.references.ReferenceFactory;
import org.apache.flex.compiler.exceptions.BuildCanceledException;
import org.apache.flex.compiler.internal.definitions.ClassDefinition;
import org.apache.flex.compiler.internal.projects.CompilerProject;
import org.apache.flex.compiler.internal.projects.FlexProject;
import org.apache.flex.compiler.internal.scopes.ASProjectScope;
import org.apache.flex.compiler.internal.units.SWCCompilationUnit;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.targets.ISWFTarget;
import org.apache.flex.compiler.targets.ITargetProgressMonitor;
import org.apache.flex.compiler.targets.ITargetReport;
import org.apache.flex.compiler.targets.ITargetSettings;
import org.apache.flex.compiler.units.ICompilationUnit;
import org.apache.flex.compiler.units.ICompilationUnit.UnitType;
import org.apache.flex.swc.ISWC;
import org.apache.flex.swc.ISWCLibrary;
import org.apache.flex.swf.ISWF;
import org.apache.flex.swf.SWF;
import org.apache.flex.swf.SWFFrame;
import org.apache.flex.swf.ISWFConstants;
import org.apache.flex.swf.tags.DoABCTag;
import org.apache.flex.swf.tags.IManagedTag;
import org.apache.flex.swf.tags.ITag;
import org.apache.flex.swf.tags.ScriptLimitsTag;
import org.apache.flex.swf.tags.SymbolClassTag;
import org.apache.flex.swf.types.RGB;
import org.apache.flex.swf.types.Rect;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

/**
* Concrete implementation of ITarget for building a collection of source files
* into a SWF.
*/
public abstract class SWFTarget extends Target implements ISWFTarget
{
    protected static final class SWFFrameInfo
    {
        public static final boolean EXTERNS_ALLOWED = true;
        public static final boolean EXTERNS_DISALLOWED = false;
       
        public SWFFrameInfo(String frameLabel, boolean allowExternals, Set<ICompilationUnit> rootedUnits, Iterable<ICompilerProblem> problems)
        {
            // character replaced came from the old compiler, so copy to match behavior
            this.frameLabel = frameLabel != null ? frameLabel.replaceAll( "[^A-Za-z0-9]", "_" ) : null;
            this.allowExternals = allowExternals;
            this.rootedUnits = rootedUnits;
            this.problems = problems;
        }
       
        public SWFFrameInfo(Set<ICompilationUnit> rootedUnits, Iterable<ICompilerProblem> problems)
        {
            this(null, EXTERNS_ALLOWED, rootedUnits, problems);
        }

        public final String frameLabel;
        public final boolean allowExternals;
        public final Set<ICompilationUnit> rootedUnits;
        public final Iterable<ICompilerProblem> problems;
    }

    public SWFTarget(CompilerProject project, ITargetSettings targetSettings, ITargetProgressMonitor progressMonitor)
    {
        super(project, targetSettings, progressMonitor);
    }

    private Collection<ICompilerProblem> problemCollection;
    private Target.RootedCompilationUnits rootedCompilationUnits;
    protected Set<String> metadataDonators = new HashSet<String>();
   
    /**
     * Cached list of compilation units. This is a performance optimization to keep us from
     * making redundant calls to topologicalSort.
     *
     * Note that this optimization only gives a small boost in observed cases.
     *
     * if non-null, this is the results of calling project.getReachableCompilationUnitsInSWFOrder(rootedCU);
     * We will assume it doesn't change
     */
   
    private List<ICompilationUnit> rootedCompilationUnitsAndDependenciesInSWFOrder;
   
    /**
     * Cached information about all the frames in the SWF.
     */
    private FramesInformation framesInformation;
   
    /**
     * Cached {@link RGB} value for the SWF's background color.
     */
    private RGB swfBackgroundColor;
   
   
    /**
     * Cached {@link ITargetAttributes} for the SWF
     */
    private ITargetAttributes _targetAttributes;
  
    /**
     * Gets the set of {@link ICompilationUnit}s that are the roots of the graph of
     * {@link ICompilationUnit}s whose output will be in the generate SWF.
     * @return The set of {@link ICompilationUnit}s that are the roots of the graph of
     * {@link ICompilationUnit}s whose output will be in the generate SWF
     */
    @Override
    public RootedCompilationUnits getRootedCompilationUnits() throws InterruptedException
    {
        if (rootedCompilationUnits == null)
            rootedCompilationUnits = computeRootedCompilationUnits();
        return rootedCompilationUnits;
    }
   
    /**
     * Same as project.getReachableCompilationUnitsInSWFOrder(), but with a cache for the case of rooted compilation units
     * @throws InterruptedException
     */
    List<ICompilationUnit> getReachableCompilationUnitsInSWFOrder( Collection<ICompilationUnit> roots ) throws InterruptedException
    {
        List<ICompilationUnit> ret = null;
       
        final RootedCompilationUnits rootedCompilationUnits = getRootedCompilationUnits();
       
        // Determine if the "roots" in this call are the rooted compilation units for this target.
        // We only cached the results for this case
        boolean passedInRootedCompilationUnits = false;
        if (roots.size() == rootedCompilationUnits.getUnits().size())
        {
            passedInRootedCompilationUnits = true;
            for (ICompilationUnit cu : roots)
            {
                if (!rootedCompilationUnits.getUnits().contains(cu))
                    passedInRootedCompilationUnits = false;
            }
        }
       
        // If this is the case that is cached, then get/make the cache
        if (passedInRootedCompilationUnits)
        {
            if (rootedCompilationUnitsAndDependenciesInSWFOrder == null)
            {
                rootedCompilationUnitsAndDependenciesInSWFOrder =  project.getReachableCompilationUnitsInSWFOrder(roots);          
            }
            ret = rootedCompilationUnitsAndDependenciesInSWFOrder;
        }
        else
        {
            // If not the cached case, just call the function directly
            ret = project.getReachableCompilationUnitsInSWFOrder(roots);
        }
        assert ret != null;
       
        return ret;
    }
    
    /**
     * Absolute path of the path that contains the reference to Object.
     * We use this to determine which SWC contains native code so that
     * we always exclude all of the definitions from that SWC.
     */
    private String pathContainingObject;

    @Override
    public ISWF build(Collection<ICompilerProblem> problems)
    {
        buildStarted();
        try
        {
            Iterable<ICompilerProblem> fatalProblems = getFatalProblems();
            if (!Iterables.isEmpty(fatalProblems))
            {
                Iterables.addAll(problems, fatalProblems);
                return null;
            }

            Set<ICompilationUnit> compilationUnitSet = new HashSet<ICompilationUnit>();
            Target.RootedCompilationUnits rootedCompilationUnits = getRootedCompilationUnits();
           
            // no rooted compilation could be found, but still create an empty SWF
            // in this error case
            if (rootedCompilationUnits.getUnits().isEmpty())
                return buildEmptySWF();

            compilationUnitSet.addAll(rootedCompilationUnits.getUnits());

            this.problemCollection = problems;

            FramesInformation frames = getFramesInformation();
           
            BuiltCompilationUnitSet builtCompilationUnits =
                getBuiltCompilationUnitSet();
            Iterables.addAll(problems, builtCompilationUnits.problems);
           
            doPostBuildWork(builtCompilationUnits.compilationUnits, problems);
           
            ISWF swf = initializeSWF(getReachableCompilationUnitsInSWFOrder(rootedCompilationUnits.getUnits()));
           
            // now that everything is built, the dependency graph is populated enough to do a topological sort on
            // all compilation units needed by this target.
            // The compilation units that define bases classes must occurs in the swf before
            // compilation units that define classes that subclass those classes ( see
            // inheritance dependencies in the {@link DependencyGraph} ).
            Set<ICompilationUnit> emittedCompilationUnits = new HashSet<ICompilationUnit>();
           
            frames.createFrames(this, swf, builtCompilationUnits.compilationUnits, emittedCompilationUnits, problems);
           
            createLinkReport(problems);
           
            // "Link" the resulting swf, if the optimize flag is set
            return linkSWF(swf);
        }
        catch (BuildCanceledException bce)
        {
            return null;
        }
        catch (InterruptedException ie)
        {
            return null;
        }
        finally
        {
            buildFinished();
        }
    }

    @Override
    public TargetType getTargetType()
    {
        return TargetType.SWF;
    }
  
    protected final ITargetAttributes getTargetAttributes() throws InterruptedException
    {
        // if already computed, just return the cached value
        if (_targetAttributes == null)
        {
            // first time - delegate to subclass to compute
            _targetAttributes = computeTargetAttributes();
        }
        return _targetAttributes;
    }
   
    /**
     * round-up  user specified target attributes
     * All derived classes must provide one, but they are free to provide "do nothing" implementations
     * (like NilTargetAttributes)
     */
    protected abstract ITargetAttributes computeTargetAttributes() throws InterruptedException;
   
    /**
     * Create the {@link FramesInformation} which contains the skeleton for the frames
     * of this SWF. The actual frames will be create in doCreateFrames().
     * @throws InterruptedException
     */
    protected abstract FramesInformation computeFramesInformation() throws InterruptedException;
   
    protected final FramesInformation getFramesInformation() throws InterruptedException
    {
        if (framesInformation != null)
            return framesInformation;
        framesInformation = computeFramesInformation();
        return framesInformation;
    }
   
    /**
     * Check the build and analyze the results before the SWF target is
     * initialized.
     *
     * @param compilationUnits The set of compilation units after
     * buildAndCollectProblems() has run.
     * @param problems A collection where discovered problems are appended.
     */
    protected void doPostBuildWork(ImmutableSet<ICompilationUnit> compilationUnits,
            Collection<ICompilerProblem> problems) throws InterruptedException
    {
       
    }

    /**
     * Creates a new instance of a SWF.
     *
     * @return a new instance of a SWF.
     */
    protected SWF buildEmptySWF()
    {
        return new SWF();
    }

    /**
     * Add to the collection of compiler problems.
     *
     * @param problem
     */
    protected void reportProblem(ICompilerProblem problem)
    {
        assert problemCollection != null;
       
        problemCollection.add(problem);
    }

    /**
     * Add a set of root classes and its dependencies to a new frame or to an existing
     * frame.
     * @param frame if null a new frame will be created for the classes. Otherwise the
     * classes will be added to the existing frame.
     * @param frameRootClasses
     * @param projectScope
     * @param allowExternals
     * @param emittedCompilationUnits
     * @return The SWF frame.
     * @throws InterruptedException
     */
    protected SWFFrame createWithClassesAndItsDependencies(SWFFrame frame,
            Collection<ClassDefinition> frameRootClasses, ASProjectScope projectScope,
            boolean allowExternals,
            Set<ICompilationUnit> emittedCompilationUnits) throws InterruptedException
    {
        final List<ICompilationUnit> rootedUnitsForFrame = new LinkedList<ICompilationUnit>();
        for (ClassDefinition frameRootClass : frameRootClasses)
        {
            final Collection<IDefinition> extraDefinitions = frameRootClass.resolveExtraClasses(project);
            final ICompilationUnit frameFactoryClassCompilationUnit = projectScope.getCompilationUnitForDefinition(frameRootClass);
            assert frameFactoryClassCompilationUnit != null;
            rootedUnitsForFrame.add(frameFactoryClassCompilationUnit);
            for (IDefinition extraDef : extraDefinitions)
            {
                if (!extraDef.isImplicit())
                {
                    ICompilationUnit extraDefCompilationUnit = projectScope.getCompilationUnitForDefinition(extraDef);
                    assert extraDefCompilationUnit != null;
                    rootedUnitsForFrame.add(extraDefCompilationUnit);
                }
            }
        }

        if (frame == null)
            frame = new SWFFrame();

        if (!addCompilationUnitsAndDependenciesToFrame(frame, rootedUnitsForFrame, allowExternals, emittedCompilationUnits))
            return null;

        return frame;
    }

    protected boolean addCompilationUnitsAndDependenciesToFrame(SWFFrame frame,
            Collection<ICompilationUnit> rootedUnitsForFrame,
            boolean allowExternals,
            Set<ICompilationUnit> emittedCompilationUnits) throws InterruptedException
    {
        List<ICompilationUnit> unitsForFrame = this.getReachableCompilationUnitsInSWFOrder(rootedUnitsForFrame);
        for (ICompilationUnit cu : unitsForFrame)
        {
            if (emittedCompilationUnits.add(cu))
            {
                boolean includeCu = testCompilationUnitLinkage(cu, allowExternals);
                doAddMetadataNamesToTarget(cu, includeCu);
               
                if (includeCu)
                {
                    boolean tagsAdded = cu.getSWFTagsRequest().get().addToFrame(frame);
                    if (!tagsAdded)
                        return false;
                }
            }
        }
        return true;
    }

    /**
     * Add metadata names to the target for this compilation unit.
     *
     * @param cu
     * @param linkedIn true if the compilation unit is linked in, false if
     * external.
     */
    protected void doAddMetadataNamesToTarget(ICompilationUnit cu, boolean linkedIn)
    {
       
        if (shouldAddMetadataNamesToTarget(cu, linkedIn))
        {
            if (metadataDonators.add(cu.getAbsoluteFilename()))
            {
                ISWC swc = project.getWorkspace().getSWCManager().
                        get(new File(cu.getAbsoluteFilename()));
                for (ISWCLibrary library : swc.getLibraries())
                {
                    addASMetadataNames(library.getKeepAS3MetadataSet());
                }
            }
               
        }
    }

    /**
     * Test if any metadata names associated with the compilation unit should be
     * added to the target.
     *
     * @param cu
     * @param linkedIn true if the compilation unit is linked in, false if
     * external.
     * @return true if the metadata names should be included, false otherwise.
     */
    protected boolean shouldAddMetadataNamesToTarget(ICompilationUnit cu, boolean linkedIn)
    {
        return (cu.getCompilationUnitType() == UnitType.SWC_UNIT &&
                !isLinkageAlwaysExternal(cu));
    }

    /**
     * Test if a compilation unit should be include in this target.
     *
     * @param cu
     * @param allowExternals
     * @return True if the compilation should be included, false otherwise.
     * @throws InterruptedException
     */
    protected boolean testCompilationUnitLinkage(ICompilationUnit cu, boolean allowExternals) throws InterruptedException
    {
        boolean includeCu = true;
       
        if (!allowExternals)
            includeCu = !isLinkageAlwaysExternal(cu);
        else if (isLinkageExternal(cu, targetSettings))
            includeCu = false;
       
        return includeCu;
    }

    /**
     * Test if this compilation unit should always be externalized. Native code
     * cannot be included in an application. We for test native code by checking
     * for the SWC that contains the definition of Object and externalize all of
     * the classes in that SWC. Compilation units that come from an ANE are also
     * always externalized.
     *
     * @param cu
     * @return true if the compilation unit should always be externalized, false
     * otherwise.
     */
    private boolean isLinkageAlwaysExternal(ICompilationUnit cu)
    {
        if (cu.getCompilationUnitType() != UnitType.SWC_UNIT)
            return false;
       
        // Find the SWC that contains Object.
        if (pathContainingObject == null)
        {
            IResolvedQualifiersReference objectReference = ReferenceFactory.packageQualifiedReference(
                    project.getWorkspace(),
                    IASLanguageConstants.Object);
            Set<ICompilationUnit> units = project.getScope().
                    getCompilationUnitsForReferences(Collections.singletonList(objectReference));
            assert units.size() == 1;
           
            pathContainingObject = units.iterator().next().getAbsoluteFilename();
            assert pathContainingObject != null;
        }
       
        // If this compilation unit comes from the same SWC as the SWC that
        // contains Object then we must always extern the class.
        if (pathContainingObject.equals(cu.getAbsoluteFilename()))
            return true;
       
        // Test if the compilation unit is from an ANE file.
        if (cu instanceof SWCCompilationUnit)
            return ((SWCCompilationUnit)cu).isANE();
       
        return false;
    }
   
    protected abstract void addLinkedABCToFrame(SWFFrame targetFrame, Iterable<DoABCTag> inputABCs, ABCLinker.ABCLinkerSettings linkSettings) throws Exception;
   
    protected abstract void setKeepAS3MetadataLinkerSetting(ABCLinker.ABCLinkerSettings linkSettings);
   
    /**
     * Link the swf - this handles merging the DoABC tags inside each frame, and will
     * also handle stripping debug opcodes, optimizing the abcs, and/or stripping metadata
     * @param unLinked  the SWF to process
     * @return          A SWF that is the resulting of merging, optimizing, etc.
     */
    protected ISWF linkSWF(ISWF unLinked)
    {
        SWF result = new SWF();
        if( unLinked.getBackgroundColor() != null )
            result.setBackgroundColor(unLinked.getBackgroundColor());
        result.setEnableDebugger2(unLinked.getEnableDebugger2());
        result.setFrameRate(unLinked.getFrameRate());
        result.setFrameSize(unLinked.getFrameSize());
        result.setMetadata(unLinked.getMetadata());
        ScriptLimitsTag scriptLimits = unLinked.getScriptLimits();
        if (scriptLimits != null)
            result.setScriptLimits(scriptLimits.getMaxRecursionDepth(), scriptLimits.getScriptTimeoutSeconds());
        result.setTopLevelClass(unLinked.getTopLevelClass());
        result.setUseAS3(unLinked.getUseAS3());
        result.setUseDirectBlit(unLinked.getUseDirectBlit());
        result.setUseGPU(unLinked.getUseGPU());
        result.setUseNetwork(unLinked.getUseNetwork());
        result.setVersion(unLinked.getVersion());
        result.setProductInfo(unLinked.getProductInfo());
       
        ITargetSettings settings = getTargetSettings();

        ABCLinker.ABCLinkerSettings linkSettings = new ABCLinker.ABCLinkerSettings();

        linkSettings.setOptimize(settings.isOptimized());
        linkSettings.setEnableInlining(project.isInliningEnabled());
        linkSettings.setStripDebugOpcodes(!settings.isDebugEnabled());
        linkSettings.setStripGotoDefinitionHelp(!settings.isDebugEnabled());
        linkSettings.setStripFileAttributeFromGotoDefinitionHelp(settings.isOptimized());
        linkSettings.setProblemsCollection(this.problemCollection);
        linkSettings.setRemoveDeadCode(settings.getRemoveDeadCode());
       
        Collection<String> metadataNames = getASMetadataNames();
        if (settings.isDebugEnabled() && metadataNames != null)
        {
            Collection<String> names = new ArrayList<String>(metadataNames);
            names.add(IMetaAttributeConstants.ATTRIBUTE_GOTODEFINITIONHELP);
            names.add(IMetaAttributeConstants.ATTRIBUTE_GOTODEFINITION_CTOR_HELP);
            metadataNames = names;
        }
       
        setKeepAS3MetadataLinkerSetting(linkSettings);

        for (int i = 0; i < unLinked.getFrameCount(); ++i)
        {
            SWFFrame unlinkedFrame = unLinked.getFrameAt(i);
            SWFFrame resultFrame = new SWFFrame();

            if( unlinkedFrame.getName() != null )
                resultFrame.setName(unlinkedFrame.getName(), unlinkedFrame.hasNamedAnchor());

            LinkedList<DoABCTag> accumulatedABC = new LinkedList<DoABCTag>();
            for (ITag unlinkedTag : unlinkedFrame)
            {
                if (unlinkedTag instanceof DoABCTag)
                {
                    final DoABCTag abcTag = (DoABCTag)unlinkedTag;
                    accumulatedABC.add(abcTag);                       
                }
                else
                {
                    if (!accumulatedABC.isEmpty())
                    {
                        try
                        {
                            addLinkedABCToFrame(resultFrame, accumulatedABC, linkSettings);
                        }
                        catch (Exception e)
                        {
                            return unLinked;
                        }
                        accumulatedABC.clear();
                    }
                   
                    if (!(unlinkedTag instanceof IManagedTag))
                    {
                        resultFrame.addTag(unlinkedTag);
                    }
                    else if( unlinkedTag instanceof SymbolClassTag )
                    {
                        SymbolClassTag s = (SymbolClassTag)unlinkedTag;
                        for( String symbol_name : s.getSymbolNames() )
                        {
                            resultFrame.defineSymbol(s.getSymbol(symbol_name), symbol_name);
                        }
                    }
                }
            }
            if (!accumulatedABC.isEmpty())
            {
                try
                {
                    addLinkedABCToFrame(resultFrame, accumulatedABC, linkSettings);
                }
                catch (Exception e)
                {
                    return unLinked;
                }
                accumulatedABC.clear();
            }
            result.addFrame(resultFrame);
        }
       
        return result;
    }

    /**
     * {@inheritDoc}
     * <p>
     * For {@link SWFTarget}'s the set of rooted {@link ICompilationUnit}s is computed
     * by enumerating all the frames and collecting all the {@link ICompilationUnit}s assigned
     * to each of the frames.
     */
    @Override
    protected RootedCompilationUnits computeRootedCompilationUnits() throws InterruptedException
    {
        final FramesInformation framesInfo = getFramesInformation();
        final RootedCompilationUnits rootedCompilationUnits =
            new RootedCompilationUnits(ImmutableSet.copyOf(framesInfo.getAllCompilationUnits()), framesInfo.getProblems());
        return rootedCompilationUnits;
    }
   
    /**
     * Initialize SWF model with default header values from the target settings
     * when not overridden by the target attributes.
     *
     * @return SWF model.
     * @throws InterruptedException
     */
    protected ISWF initializeSWF(List<ICompilationUnit> reachableCompilationUnits) throws InterruptedException
    {
        int swfVersion = targetSettings.getSWFVersion();

        int swfWidth = targetSettings.getDefaultWidth();
       
        ITargetAttributes targetAttributes = getTargetAttributes();
        Float attrWidth = targetAttributes.getWidth();
        if (attrWidth != null)
            swfWidth = attrWidth.intValue();

        int swfHeight = targetSettings.getDefaultHeight();
        Float attrHeight = targetAttributes.getHeight();
        if (attrHeight != null)
            swfHeight = attrHeight.intValue();

        Rect swfFrameSize = new Rect(ISWFConstants.TWIPS_PER_PIXEL * swfWidth,
                                  ISWFConstants.TWIPS_PER_PIXEL * swfHeight);

        float swfFrameRate = targetSettings.getDefaultFrameRate();
        Float attrFrameRate = targetAttributes.getFrameRate();
        if (attrFrameRate != null)
            swfFrameRate = attrFrameRate.floatValue();

        boolean swfUseDirectBlit = targetSettings.useDirectBlit();
        Boolean attrUseDirectBlit = targetAttributes.getUseDirectBlit();
        if (attrUseDirectBlit != null)
            swfUseDirectBlit = attrUseDirectBlit.booleanValue();

        boolean swfUseGPU = targetSettings.useGPU();
        Boolean attrUseGPU = targetAttributes.getUseGPU();
        if (attrUseGPU != null)
            swfUseGPU = attrUseGPU.booleanValue();

       
        final RGB swfBackgroundColorRGB = getBackgroundColor();

        SWF swf = new SWF();
        swf.setVersion(swfVersion);
        swf.setFrameSize(swfFrameSize);
        swf.setFrameRate(swfFrameRate);
        swf.setUseDirectBlit(swfUseDirectBlit);
        swf.setUseGPU(swfUseGPU);
        swf.setBackgroundColor(swfBackgroundColorRGB);
        swf.setUseAS3(swfVersion >= 9);
        swf.setUseNetwork(targetSettings.useNetwork());
        swf.setMetadata(targetSettings.getSWFMetadata());
       
        // Apply the ScriptLimits tag, but only if limits have been specified
        // either in the targetSettings or targetAttributes
        Integer attrScriptRecursionLimit = targetAttributes.getScriptRecursionLimit();
        Integer attrScriptTimeLimit = targetAttributes.getScriptTimeLimit();
        if (targetSettings.areDefaultScriptLimitsSet() || attrScriptRecursionLimit != null || attrScriptTimeLimit != null)
        {
            int swfMaxRecursionDepth = targetSettings.getDefaultScriptRecursionLimit();
            if (attrScriptRecursionLimit != null)
                swfMaxRecursionDepth = attrScriptRecursionLimit.intValue();

            int swfScriptTimeoutSeconds = targetSettings.getDefaultScriptTimeLimit();
            if (attrScriptTimeLimit != null)
                swfScriptTimeoutSeconds = attrScriptTimeLimit.intValue();

            swf.setScriptLimits(swfMaxRecursionDepth, swfScriptTimeoutSeconds);
        }

        return swf;
    }
   
    protected final RGB getBackgroundColor()  throws InterruptedException
    {
        if (swfBackgroundColor != null)
            return swfBackgroundColor;
       
        int swfBackgroundColorInt = targetSettings.getDefaultBackgroundColor();
        String attrBackgroundColorString = getTargetAttributes().getBackgroundColor();
        if (!Strings.isNullOrEmpty(attrBackgroundColorString))
        {
            if (project instanceof FlexProject)
                swfBackgroundColorInt = ((FlexProject)project).getColorAsInt(attrBackgroundColorString);
            else
                swfBackgroundColorInt = Integer.decode(attrBackgroundColorString).intValue();
        }
        swfBackgroundColor = new RGB(swfBackgroundColorInt);
        return swfBackgroundColor;
    }
   
    @Override
    protected ITargetReport computeTargetReport() throws InterruptedException
    {
        BuiltCompilationUnitSet builtCompilationUnits = getBuiltCompilationUnitSet();
       
        return new TargetReport(project, builtCompilationUnits.compilationUnits, Collections.<RSLSettings>emptyList(),
                getBackgroundColor(), targetSettings, getTargetAttributes(), getLinkageChecker());
    }
   
    /**
     * Contains information about the skeleton of a SWF that is being built by
     * a {@link SWFTarget} and provides methods to create {@link SWFFrame}s and add them
     * to a {@link ISWF}.
     */
    protected static class FramesInformation
    {
        public FramesInformation(Iterable<SWFFrameInfo> frameInfos)
        {
            this.frameInfos = frameInfos;
        }
       
        /**
         * {@link Iterable} of {@link SWFFrameInfo}s which represents the
         * skeleton of a SWF being built by a {@link SWFTarget}.
         */
        public final Iterable<SWFFrameInfo> frameInfos;
       
        /**
         * @return An {@link Iterable} of {@link ICompilerProblem}s that can be
         * used to iterate all the {@link ICompilerProblem}s found while
         * building the skeleton of a SWF being built by a {@link SWFTarget}.
         */
        final Iterable<ICompilerProblem> getProblems()
        {
            Iterable<Iterable<ICompilerProblem>> problemIterables =
                Iterables.transform(frameInfos, new Function<SWFFrameInfo, Iterable<ICompilerProblem>>() {

                    @Override
                    public Iterable<ICompilerProblem> apply(SWFFrameInfo frame)
                    {
                        return frame.problems;
                    }});
           
            return Iterables.concat(problemIterables);
        }
       
        /**
         * @return An {@link Iterable} of {@link ICompilationUnit}s that are rooted by
         * the skeleton of a SWF buing built by a {@link SWFTarget}.
         */
        final Iterable<ICompilationUnit> getAllCompilationUnits()
        {
            Iterable<Iterable<ICompilationUnit>> compilationUnitIterables =
                Iterables.transform(frameInfos, new Function<SWFFrameInfo, Iterable<ICompilationUnit>>() {

                    @Override
                    public Iterable<ICompilationUnit> apply(SWFFrameInfo frame)
                    {
                        return frame.rootedUnits;
                    }});
            return Iterables.concat(compilationUnitIterables);
        }
       
        /**
         * Creates a {@link SWFFrame} for a {@link SWFFrameInfo}.
         *
         * @param swfTarget The {@link SWFTarget} that is building the SWF to
         * which the newly created {@link SWFFrame} will be added.
         * @param frameInfo The {@link SWFFrameInfo} that represents the skeleton
         * of the SWF frame to create.
         * @param builtCompilationUnits The {@link ImmutableSet} of
         * {@link ICompilationUnit}s that have been built to create the SWF
         * being built by the specified {@link SWFTarget}. This {@link Set} is
         * used to write an assert.
         * @param emittedCompilationUnits The {@link Set} of
         * {@link ICompilationUnit}s that any {@link ICompilationUnit}s added to
         * this frame should be added to. This {@link Set} is used to ensure
         * that each {@link ICompilationUnit} is only added to a single frame in
         * a SWF.
         * @param problems {@link Collection} of {@link ICompilerProblem}s that
         * any {@link ICompilerProblem}s from any {@link ICompilationUnit} added
         * to the new {@link SWFFrame} should be added to.
         * @return A new {@link SWFFrame}.
         * @throws InterruptedException
         */
        protected final SWFFrame createFrame(SWFTarget swfTarget, SWFFrameInfo frameInfo, ImmutableSet<ICompilationUnit> builtCompilationUnits, Set<ICompilationUnit> emittedCompilationUnits, Collection<ICompilerProblem> problems) throws InterruptedException
        {
            Iterables.addAll(problems, frameInfo.problems);
           
            final SWFFrame swfFrame = new SWFFrame();
           
            if (frameInfo.frameLabel != null)
                swfFrame.setName(frameInfo.frameLabel, true);
           
            assert Sets.difference(frameInfo.rootedUnits, builtCompilationUnits).isEmpty()
                : "All compilation units to emit on this frame should have been built!";
           
            if (!swfTarget.addCompilationUnitsAndDependenciesToFrame(swfFrame, frameInfo.rootedUnits,
                    frameInfo.allowExternals, emittedCompilationUnits))
            {
                return null;               
            }
            return swfFrame;
        }
       
        /**
         * Creates all the {@link SWFFrame}s for the SWF skeleton represented by
         * this {@link FramesInformation} and adds them to the specified
         * {@link ISWF}.
         * <p>
         * This method is overridden by sub-classes of {@link FramesInformation}.
         *
         * @param swfTarget The {@link SWFTarget} that is building the SWF to
         * which the newly created {@link SWFFrame}s will be added.
         * @param swf The {@link ISWF} to which the new created {@link SWFFrame}
         * s will be added.
         * @param builtCompilationUnits The {@link ImmutableSet} of
         * {@link ICompilationUnit}s that have been built to create the SWF
         * being built by the specified {@link SWFTarget}. Sub-classes use this
         * set to generate code that supports startup of the Flex framework.
         * @param emittedCompilationUnits The {@link Set} of
         * {@link ICompilationUnit}s that any {@link ICompilationUnit}s added to
         * this frame should be added to. This {@link Set} is used to ensure
         * that each {@link ICompilationUnit} is only added to a single frame in
         * a SWF.
         * @param problems {@link Collection} of {@link ICompilerProblem}s that
         * any {@link ICompilerProblem}s from any {@link ICompilationUnit} added
         * to the new {@link SWFFrame}s should be added to.
         * @throws InterruptedException
         */
        protected void createFrames(SWFTarget swfTarget, ISWF swf, ImmutableSet<ICompilationUnit> builtCompilationUnits, Set<ICompilationUnit> emittedCompilationUnits, Collection<ICompilerProblem> problems) throws InterruptedException
        {
            for (final SWFFrameInfo frameInfo : frameInfos)
            {
                SWFFrame swfFrame = createFrame(swfTarget, frameInfo, builtCompilationUnits, emittedCompilationUnits, problems);
                swf.addFrame(swfFrame);
            }
        }
    }
   
}
TOP

Related Classes of org.apache.flex.compiler.internal.targets.SWFTarget$FramesInformation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.