flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cd...@apache.org
Subject [19/51] [partial] - Migrated the directory structure to a more Maven style structure. - Started migrating the Parser from Antlr2+3 and JFlex to Antlr4.
Date Tue, 22 Jul 2014 13:35:45 GMT
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/compiler/fxg/swf/FXG2SWFTranscoder.java
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/compiler/fxg/swf/FXG2SWFTranscoder.java b/compiler/src/main/java/org/apache/flex/compiler/fxg/swf/FXG2SWFTranscoder.java
new file mode 100644
index 0000000..444cdbd
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/compiler/fxg/swf/FXG2SWFTranscoder.java
@@ -0,0 +1,1663 @@
+/*
+ *
+ *  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.fxg.swf;
+
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.PathIterator;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.flex.compiler.definitions.ITypeDefinition;
+import org.apache.flex.compiler.fxg.FXGConstants;
+import org.apache.flex.compiler.fxg.IFXGTranscoder;
+import org.apache.flex.compiler.fxg.dom.IFXGNode;
+import org.apache.flex.compiler.fxg.flex.FXGSymbolClass;
+import org.apache.flex.compiler.fxg.resources.IFXGResourceResolver;
+import org.apache.flex.compiler.internal.fxg.dom.AbstractShapeNode;
+import org.apache.flex.compiler.internal.fxg.dom.BitmapGraphicNode;
+import org.apache.flex.compiler.internal.fxg.dom.DefinitionNode;
+import org.apache.flex.compiler.internal.fxg.dom.EllipseNode;
+import org.apache.flex.compiler.internal.fxg.dom.IFillNode;
+import org.apache.flex.compiler.internal.fxg.dom.IFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.GradientEntryNode;
+import org.apache.flex.compiler.internal.fxg.dom.GraphicContentNode;
+import org.apache.flex.compiler.internal.fxg.dom.GraphicContext;
+import org.apache.flex.compiler.internal.fxg.dom.GraphicNode;
+import org.apache.flex.compiler.internal.fxg.dom.GroupDefinitionNode;
+import org.apache.flex.compiler.internal.fxg.dom.GroupNode;
+import org.apache.flex.compiler.internal.fxg.dom.LineNode;
+import org.apache.flex.compiler.internal.fxg.dom.IMaskableNode;
+import org.apache.flex.compiler.internal.fxg.dom.IMaskingNode;
+import org.apache.flex.compiler.internal.fxg.dom.PathNode;
+import org.apache.flex.compiler.internal.fxg.dom.PlaceObjectNode;
+import org.apache.flex.compiler.internal.fxg.dom.RectNode;
+import org.apache.flex.compiler.internal.fxg.dom.RichTextNode;
+import org.apache.flex.compiler.internal.fxg.dom.IStrokeNode;
+import org.apache.flex.compiler.internal.fxg.dom.TextGraphicNode;
+import org.apache.flex.compiler.internal.fxg.dom.fills.BitmapFillNode;
+import org.apache.flex.compiler.internal.fxg.dom.fills.LinearGradientFillNode;
+import org.apache.flex.compiler.internal.fxg.dom.fills.RadialGradientFillNode;
+import org.apache.flex.compiler.internal.fxg.dom.fills.SolidColorFillNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.BevelFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.BlurFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.ColorMatrixFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.DropShadowFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.GlowFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.GradientBevelFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.filters.GradientGlowFilterNode;
+import org.apache.flex.compiler.internal.fxg.dom.strokes.AbstractStrokeNode;
+import org.apache.flex.compiler.internal.fxg.dom.strokes.LinearGradientStrokeNode;
+import org.apache.flex.compiler.internal.fxg.dom.strokes.RadialGradientStrokeNode;
+import org.apache.flex.compiler.internal.fxg.dom.strokes.SolidColorStrokeNode;
+import org.apache.flex.compiler.internal.fxg.dom.transforms.ColorTransformNode;
+import org.apache.flex.compiler.internal.fxg.dom.transforms.MatrixNode;
+import org.apache.flex.compiler.internal.fxg.dom.types.BevelType;
+import org.apache.flex.compiler.internal.fxg.dom.types.BlendMode;
+import org.apache.flex.compiler.internal.fxg.dom.types.Caps;
+import org.apache.flex.compiler.internal.fxg.dom.types.InterpolationMethod;
+import org.apache.flex.compiler.internal.fxg.dom.types.Joints;
+import org.apache.flex.compiler.internal.fxg.dom.types.MaskType;
+import org.apache.flex.compiler.internal.fxg.dom.types.ScaleMode;
+import org.apache.flex.compiler.internal.fxg.dom.types.ScalingGrid;
+import org.apache.flex.compiler.internal.fxg.dom.types.SpreadMethod;
+import org.apache.flex.compiler.internal.fxg.dom.types.Winding;
+import org.apache.flex.compiler.internal.fxg.swf.DefineImage;
+import org.apache.flex.compiler.internal.fxg.swf.ImageHelper;
+import org.apache.flex.compiler.internal.fxg.swf.ShapeHelper;
+import org.apache.flex.compiler.internal.fxg.swf.TypeHelper;
+import org.apache.flex.compiler.internal.fxg.types.FXGMatrix;
+import org.apache.flex.compiler.problems.FXGErrorEmbeddingImageProblem;
+import org.apache.flex.compiler.problems.FXGMissingAttributeProblem;
+import org.apache.flex.compiler.problems.FXGMissingGroupChildNodeProblem;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.swf.ISWFConstants;
+import org.apache.flex.swf.builders.IShapeIterator;
+import org.apache.flex.swf.builders.ShapeBuilder;
+import org.apache.flex.swf.tags.DefineScalingGridTag;
+import org.apache.flex.swf.tags.DefineShape4Tag;
+import org.apache.flex.swf.tags.DefineShapeTag;
+import org.apache.flex.swf.tags.DefineSpriteTag;
+import org.apache.flex.swf.tags.ICharacterTag;
+import org.apache.flex.swf.tags.ITag;
+import org.apache.flex.swf.tags.PlaceObject3Tag;
+import org.apache.flex.swf.types.BevelFilter;
+import org.apache.flex.swf.types.BlurFilter;
+import org.apache.flex.swf.types.CXFormWithAlpha;
+import org.apache.flex.swf.types.DropShadowFilter;
+import org.apache.flex.swf.types.FillStyle;
+import org.apache.flex.swf.types.FillStyleArray;
+import org.apache.flex.swf.types.Filter;
+import org.apache.flex.swf.types.FocalGradient;
+import org.apache.flex.swf.types.GlowFilter;
+import org.apache.flex.swf.types.GradRecord;
+import org.apache.flex.swf.types.Gradient;
+import org.apache.flex.swf.types.GradientBevelFilter;
+import org.apache.flex.swf.types.GradientGlowFilter;
+import org.apache.flex.swf.types.LineStyle;
+import org.apache.flex.swf.types.LineStyle2;
+import org.apache.flex.swf.types.LineStyleArray;
+import org.apache.flex.swf.types.Matrix;
+import org.apache.flex.swf.types.RGB;
+import org.apache.flex.swf.types.RGBA;
+import org.apache.flex.swf.types.Rect;
+import org.apache.flex.swf.types.Shape;
+import org.apache.flex.swf.types.ShapeRecord;
+import org.apache.flex.swf.types.ShapeWithStyle;
+import org.apache.flex.swf.types.Styles;
+
+/**
+ * Transcodes an FXG DOM into a tree of SWF DefineSpriteTags which use SWF graphics
+ * primitives to draw the document.
+ * Note that in this implementation, since FTE based text
+ * has no equivalent in SWF tags, text nodes are ignored.
+ */
+public class FXG2SWFTranscoder implements IFXGTranscoder
+{
+    protected FXGSymbolClass graphicClass;
+    protected HashMap<String, DefineSpriteTag> definitions;
+    protected Stack<DefineSpriteTag> spriteStack;
+    protected Map<DefineSpriteTag, Integer> depthMap;
+    protected IFXGResourceResolver resourceResolver;
+    protected Map<ITag, ITag> extraTags;
+    protected Map<String, DefineImage> imageMap;
+    protected Collection<ICompilerProblem> problems;
+    
+    public FXG2SWFTranscoder newInstance()
+    {
+        FXG2SWFTranscoder transcoder = new FXG2SWFTranscoder();;
+        transcoder.extraTags = extraTags;
+        transcoder.imageMap = imageMap;
+        transcoder.depthMap = depthMap;
+        return transcoder;
+    }
+    
+    @Override
+    public void setResourceResolver(IFXGResourceResolver resolver)
+    {
+        resourceResolver = resolver;
+    }
+
+    protected int getSpriteDepth(DefineSpriteTag sprite)
+    {
+        if(depthMap.containsKey(sprite))
+            return depthMap.get(sprite);
+        else
+            depthMap.put(sprite, 0);
+            return 0;
+    }
+    
+    private void setSpriteDepth(DefineSpriteTag sprite, Integer depth)
+    {
+        depthMap.put(sprite, depth);
+    }
+    
+    @Override
+    public FXGSymbolClass transcode(IFXGNode fxgNode, String packageName, String className, Map<ITag, ITag> extraTags, Collection<ICompilerProblem> problems)
+    {
+        this.problems = problems;
+        this.extraTags = extraTags;
+        graphicClass = new FXGSymbolClass();
+        graphicClass.setPackageName(packageName);
+        graphicClass.setClassName(className);
+        
+        GraphicNode node = (GraphicNode)fxgNode;
+        DefineSpriteTag sprite = createDefineSpriteTag("Graphic");
+        spriteStack.push(sprite);
+        
+        // Process mask (if present)
+        if (node.mask != null)
+            mask(node, sprite);
+
+        // Handle 'scale 9' grid definition
+        if (node.definesScaleGrid())
+        {
+            DefineScalingGridTag grid = createDefineScalingGridTag(node.getScalingGrid());
+            grid.setCharacter(sprite);
+            extraTags.put(sprite, grid);
+            //sprite.scalingGrid = grid;
+        }
+
+        // Process child nodes
+        if (node.children != null)
+            graphicContentNodes(node.children);
+
+        spriteStack.pop();
+        
+        graphicClass.setSymbol(sprite);
+        return graphicClass;
+    }
+
+    public FXG2SWFTranscoder()
+    {
+        spriteStack = new Stack<DefineSpriteTag>();
+        depthMap = new HashMap<DefineSpriteTag, Integer>();
+        imageMap = new HashMap<String, DefineImage>();
+    }
+    
+
+    private PlaceObject3Tag bitmapWithClip(DefineImage defImage, BitmapGraphicNode node)
+    {
+        GraphicContext context = node.createGraphicContext();
+
+        //process the filters later to avoid masking
+        List<IFilterNode> filters = null;
+        if (context.filters != null)       
+        {   
+            filters = context.filters;
+            context.filters = null;
+            DefineSpriteTag filterSprite = createDefineSpriteTag("MaskFilter");
+            spriteStack.push(filterSprite);
+        }
+        
+        DefineSpriteTag imageSprite = createDefineSpriteTag("BitmapGraphic");
+        spriteStack.push(imageSprite);
+        
+        // First, generate the clipping mask
+        DefineSpriteTag clipSprite = createDefineSpriteTag("BitmapGraphic_Clip");
+        spriteStack.push(clipSprite);
+        
+        double width = (defImage.getWidth() < node.width) ? defImage.getWidth() : node.width;
+        double height = (defImage.getHeight() < node.height) ? defImage.getHeight() : node.height;
+        List<ShapeRecord> shapeRecords = ShapeHelper.rectangle(0.0, 0.0, width, height);
+        DefineShapeTag clipShape = createDefineShapeTag(null, shapeRecords, new SolidColorFillNode(), null, context.getTransform());
+        PlaceObject3Tag(clipShape, new GraphicContext());
+        spriteStack.pop();
+        
+        //place the clipping mask in the imageSprite
+        PlaceObject3Tag po3clip = PlaceObject3Tag(clipSprite, context);
+        po3clip.setClipDepth(po3clip.getDepth()+1); 
+        po3clip.setHasClipDepth(true);
+        // Then, process the image
+        DefineShapeTag imageShape = ImageHelper.createShapeForImage(defImage, node);
+        PlaceObject3Tag(imageShape, context);        
+        spriteStack.pop();
+        
+        PlaceObject3Tag po3 = PlaceObject3Tag(imageSprite, new GraphicContext());
+        
+        // If filters were not processed, place the topmost sprite in display list and apply filters 
+        // This is done to force processing of masks before filters
+        if (filters != null)
+        {
+            DefineSpriteTag sprite = spriteStack.pop();
+            GraphicContext gc = new GraphicContext();
+            gc.filters = filters;
+            PlaceObject3Tag poFilter = PlaceObject3Tag(sprite, gc);
+            return poFilter;            
+        }
+        return po3;
+    }
+    
+    // --------------------------------------------------------------------------
+    //
+    // Graphic Content Nodes
+    //
+    // --------------------------------------------------------------------------
+    protected PlaceObject3Tag bitmap(BitmapGraphicNode node)
+    {
+        GraphicContext context = node.createGraphicContext();
+        String source = parseSource(node.source);
+
+        if (source == null)
+        {
+            // Missing source attribute in <BitmapGraphic> or <BitmapFill>.
+            problems.add(new FXGMissingAttributeProblem(node.getDocumentPath(), node.getStartLine(), 
+                    node.getStartColumn(), FXGConstants.FXG_SOURCE_ATTRIBUTE, node.getNodeName()));
+            return null;
+       }
+        
+        DefineImage imageTag = createDefineBitsTag(node, source);
+        if(imageTag == null)
+            return null;
+        
+        if ((node.visible) && (!node.isPartofClipMask))
+        {
+       
+            DefineShapeTag imageShape;
+            ScalingGrid scalingGrid = context.scalingGrid;
+            if (scalingGrid != null)
+            {
+                Rect grid = TypeHelper.rect(scalingGrid.scaleGridLeft, scalingGrid.scaleGridTop, scalingGrid.scaleGridRight, scalingGrid.scaleGridBottom);
+                imageShape = ImageHelper.create9SlicedShape(imageTag, grid, Double.NaN, Double.NaN);
+                PlaceObject3Tag po3 = PlaceObject3Tag(imageShape, context);
+                return po3;
+            }
+            else
+            {
+            	if (ImageHelper.bitmapImageNeedsClipping(imageTag, node))
+            	{
+            		PlaceObject3Tag p03 = bitmapWithClip(imageTag, node);
+            		return p03;
+            	}
+            	else
+            	{
+            		imageShape = ImageHelper.createShapeForImage(imageTag, node);
+            		PlaceObject3Tag po3 = PlaceObject3Tag(imageShape, context);
+            		return po3;
+            	}
+            }            
+        }
+        else
+        {
+        	if (!ImageHelper.bitmapImageNeedsClipping(imageTag, node))
+        	{       		
+        	     double width = (Double.isNaN(node.width)) ? imageTag.getWidth() : node.width;
+                 double height = (Double.isNaN(node.height)) ? imageTag.getHeight() : node.height;
+        		 List<ShapeRecord>  shapeRecords = ShapeHelper.rectangle(0.0, 0.0, width, height);        
+        	     DefineShapeTag shape = createDefineShapeTag(null, shapeRecords, new SolidColorFillNode(), null, context.getTransform());
+        		 PlaceObject3Tag po3 = PlaceObject3Tag(shape, context);
+        		 return po3;
+        	}
+        	else
+        	{
+                double width = ((imageTag.getWidth() < node.width) || Double.isNaN(node.width)) ? imageTag.getWidth() : node.width;
+                double height = ((imageTag.getHeight() < node.height) || (Double.isNaN(node.height))) ? imageTag.getHeight() : node.height;
+       		 	List<ShapeRecord>  shapeRecords = ShapeHelper.rectangle(0.0, 0.0, width, height);        
+       	        DefineShapeTag shape = createDefineShapeTag(null, shapeRecords, new SolidColorFillNode(), null, context.getTransform());
+       		 	PlaceObject3Tag po3 = PlaceObject3Tag(shape, context);
+       		 	return po3;
+        	}
+        }
+    }
+
+    protected void graphicContentNodes(List<GraphicContentNode> nodes)
+    {
+        if (nodes == null) return;
+        Iterator<GraphicContentNode> iterator = nodes.iterator();
+        while (iterator.hasNext())
+        {
+            GraphicContentNode node = iterator.next();
+            graphicContentNode(node);
+        }
+    }
+
+    protected PlaceObject3Tag graphicContentNode(GraphicContentNode node)
+    {
+        PlaceObject3Tag po3 = null;
+
+    	if (!node.visible)
+        {
+            ColorTransformNode ct = new ColorTransformNode();
+            ct.alphaMultiplier = 0;
+            ct.alphaOffset = 0;
+            ct.blueMultiplier = 1;
+            ct.blueOffset = 0;
+            ct.greenMultiplier = 1;
+            ct.greenOffset = 0;
+            ct.redMultiplier = 1;
+            ct.redOffset = 0;
+            node.colorTransform = ct;
+            
+            if (node instanceof AbstractShapeNode) 
+            {
+                AbstractShapeNode shapeNode = (AbstractShapeNode)node;
+                shapeNode.fill = null;
+                shapeNode.stroke = null;
+            }
+            
+        }
+
+        if (node instanceof GroupNode)
+        {
+            group((GroupNode)node);
+        }
+        else
+        {
+            if (node.blendMode == BlendMode.AUTO)
+                node.blendMode = BlendMode.NORMAL;
+            
+            // For non-group nodes, we process mask to clip only this shape
+            // node. Process the mask first to ensure the depth is correct.
+            List<IFilterNode> filters = null;
+            if (node.mask != null)
+            {
+                // Remove the filters from context and process them later to force Flash Player to process the masks first
+                if (node.filters != null)
+                {   
+                    filters = node.filters;
+                    node.filters = null;
+                    DefineSpriteTag filterSprite = createDefineSpriteTag("MaskFilter");
+                    spriteStack.push(filterSprite);
+                }
+                DefineSpriteTag parentSprite = spriteStack.peek();
+                mask(node, parentSprite);
+            }
+            
+            if (node instanceof EllipseNode)
+                po3 = ellipse((EllipseNode)node);
+            else if (node instanceof LineNode)
+                po3 = line((LineNode)node);
+            else if (node instanceof PathNode)
+                po3 = path((PathNode)node);
+            else if (node instanceof RectNode)
+                po3 = rect((RectNode)node);
+            else if (node instanceof PlaceObjectNode)
+                po3 = PlaceObject3TagInstance((PlaceObjectNode)node);
+            else if (node instanceof BitmapGraphicNode)
+                po3 = bitmap((BitmapGraphicNode)node);
+            else if (node instanceof TextGraphicNode)
+                po3 = text((TextGraphicNode)node);
+            else if (node instanceof RichTextNode)
+                po3 = richtext((RichTextNode)node);
+            
+            // If filters were not processed, place the topmost sprite in display list and apply filters 
+            // This is done to force processing of masks before filters
+            if (filters != null)
+            {
+                DefineSpriteTag sprite = spriteStack.pop();
+                GraphicContext gc = new GraphicContext();
+                gc.filters = filters;
+                PlaceObject3Tag poFilter = PlaceObject3Tag(sprite, gc);
+                return poFilter;            
+            }
+        }
+
+        return po3;
+    }
+
+    protected PlaceObject3Tag ellipse(EllipseNode node)
+    {
+        // Note that we will apply node.x and node.y as a translation operation
+        // in the PlaceObject3Tag3 Matrix and instead start the shape from the
+        // origin (0.0, 0.0).
+        Ellipse2D.Double ellipse = new Ellipse2D.Double(0.0, 0.0, node.width, node.height);
+        
+        ShapeBuilder builder = new ShapeBuilder();
+        IShapeIterator iterator = new PathIteratorWrapper(ellipse.getPathIterator(null));
+        builder.processShape(iterator);
+        Shape shape = builder.build();
+ 
+        return placeDefineShapeTag(node, shape.getShapeRecords(), node.fill, node.stroke, node.createGraphicContext());
+    }
+
+    protected PlaceObject3Tag group(GroupNode node)
+    {
+    	//handle blendMode "auto"
+        if (node.blendMode == BlendMode.AUTO)
+        {
+        	if ((node.alpha == 0) || (node.alpha == 1))
+        		node.blendMode = BlendMode.NORMAL;
+        	else
+        		node.blendMode = BlendMode.LAYER;
+        }
+        
+        DefineSpriteTag groupSprite = createDefineSpriteTag("Group");
+        GraphicContext context = node.createGraphicContext();
+        
+        // Handle 'scale 9' grid definition
+        if (node.definesScaleGrid())
+        {
+            DefineScalingGridTag grid = createDefineScalingGridTag(context.scalingGrid);
+            grid.setCharacter(groupSprite);
+            extraTags.put(groupSprite,grid);
+            //groupSprite.scalingGrid = grid;
+        }
+
+        PlaceObject3Tag po3 = PlaceObject3Tag(groupSprite, context);
+        spriteStack.push(groupSprite);
+        
+        // First, process mask (if present)
+        List <IFilterNode> filters = null;
+        if (node.mask != null)
+        {    
+            // Remove the filters from context and process them later to force Flash Player to process the masks first
+            filters = node.filters;
+            if (filters == null)
+            {
+                List<GraphicContentNode> children = node.children;
+                if (children != null)
+                {
+                    GraphicContentNode gcNode0 = (GraphicContentNode) children.get(0);
+                    filters = gcNode0.filters;
+                    if (filters != null)
+                    {
+                        //check if all the nodes share the same filter
+                        for (int i = 1; ((i < children.size()) && filters!= null); i++)
+                        {
+                            GraphicContentNode gcNodeI = (GraphicContentNode) children.get(i);
+                            if (gcNodeI.filters != filters)
+                                filters = null;
+                        }
+                    }
+
+                    if (filters != null)
+                    {
+                        for (int i = 0; (i < children.size()) ; i++)
+                        {
+                            GraphicContentNode gcNodeI = (GraphicContentNode) children.get(i);
+                            gcNodeI.filters = null;
+                        }                        
+                    }
+                    
+                }
+            }
+            else
+            {
+                node.filters = null;
+            }
+ 
+            if (filters != null)       
+            {    
+                DefineSpriteTag filterSprite = createDefineSpriteTag("MaskFilter");
+                spriteStack.push(filterSprite);
+            }
+            DefineSpriteTag sprite = spriteStack.peek();
+            mask(node, sprite);
+        }
+
+        // Then process child nodes.
+        if (node.children != null)
+            graphicContentNodes(node.children);
+        
+        // If filters were not processed, place the topmost sprite in display list and apply filters 
+        // This is done to force processing of masks before filters
+        if (filters != null)
+        {
+            DefineSpriteTag sprite = spriteStack.pop();
+            GraphicContext gc = new GraphicContext();
+            gc.filters = filters;
+            PlaceObject3Tag poFilter = PlaceObject3Tag(sprite, gc);
+            return poFilter;            
+        }
+        spriteStack.pop();
+        return po3;
+    }
+
+    protected PlaceObject3Tag line(LineNode node)
+    {
+        List<ShapeRecord> shapeRecords = ShapeHelper.line(node.xFrom, node.yFrom, node.xTo, node.yTo);
+        GraphicContext context = node.createGraphicContext();
+        PlaceObject3Tag po3 = placeDefineShapeTag(node, shapeRecords, node.fill, node.stroke, context);
+        return po3;
+    }
+
+    protected PlaceObject3Tag mask(IMaskableNode node, DefineSpriteTag parentSprite)
+    {
+        PlaceObject3Tag po3 = null;
+
+        IMaskingNode mask = node.getMask();
+        if (mask instanceof GroupNode)
+        {
+            // According to FXG Spec.: The masking element inherits the target 
+            // group's coordinate space, as though it were a direct child 
+            // element. In the case when mask is inside a shape, it doesn't 
+            // automatically inherit the coordinates from the shape node 
+            // but inherits from its parent node which is also parent of 
+            // the shape node. To fix it, specifically concatenating the 
+            // shape node matrix to the masking node matrix.
+            if (!(node instanceof GroupNode || node instanceof GraphicNode))
+            {
+                FXGMatrix nodeMatrix = null;
+                MatrixNode matrixNodeShape = ((GraphicContentNode)node).matrix;
+                if (matrixNodeShape == null)
+                    // Convert shape node's discreet transform attributes to 
+                    // matrix.
+                    nodeMatrix = FXGMatrix.convertToMatrix(((GraphicContentNode)node).scaleX, ((GraphicContentNode)node).scaleY, ((GraphicContentNode)node).rotation, ((GraphicContentNode)node).x, ((GraphicContentNode)node).y);
+                else
+                    nodeMatrix = new FXGMatrix(matrixNodeShape);
+                // Get masking node matrix.
+                MatrixNode matrixNodeMasking = ((GraphicContentNode)mask).matrix;
+                // Create a new MatrixNode if the masking node doesn't have one.
+                if (matrixNodeMasking == null)
+                {
+                    // Convert masking node's transform attributes to matrix
+                    // so we can concatenate the shape node's matrix to it.
+                    ((GraphicContentNode)mask).convertTransformAttrToMatrix(problems);
+                    matrixNodeMasking = ((GraphicContentNode)mask).matrix;
+                }
+                FXGMatrix maskMatrix = new FXGMatrix(matrixNodeMasking);
+                // Concatenate the shape node's matrix to the masking node's 
+                // matrix.
+                maskMatrix.concat(nodeMatrix);
+                // Set the masking node's matrix with the concatenated values.
+                maskMatrix.setMatrixNodeValue(matrixNodeMasking);
+            }
+            
+            markLeafNodesAsMask(node, (GroupNode) mask);
+            po3 = group((GroupNode)mask);
+        }
+        else if (mask instanceof PlaceObjectNode)
+        {
+            po3 = PlaceObject3TagInstance((PlaceObjectNode)mask);
+        }
+
+        if (po3 != null)
+        {
+            int clipDepth = 1;
+            // If we had a graphic or group, clip the depths for all children.
+            if (node instanceof GroupNode)
+            {
+                GroupNode group = (GroupNode)node;
+                if (group.children != null)
+                    clipDepth = getSpriteDepth(parentSprite) + group.children.size();
+            }
+            else if (node instanceof GraphicNode)
+            {
+                GraphicNode graphic = (GraphicNode)node;
+                if (graphic.children != null)
+                    clipDepth = getSpriteDepth(parentSprite) + graphic.children.size();
+            }
+            // ... otherwise, just clip the shape itself.
+            else
+            {//TODO
+                clipDepth = po3.getDepth() + 1;
+            }
+
+            po3.setClipDepth(clipDepth);
+            po3.setHasClipDepth(true);
+            if (node.getMaskType() == MaskType.ALPHA)
+            {
+                po3.setHasCacheAsBitmap(true);
+            }
+        }
+
+        return po3;
+    }
+
+    protected PlaceObject3Tag path(PathNode node)
+    {
+        List<ShapeRecord> shapeRecords = ShapeHelper.path(node, (node.fill != null), problems);
+        GraphicContext context = node.createGraphicContext();
+        Winding winding[] = new Winding[1];
+        winding[0] = node.winding;
+        PlaceObject3Tag po3 = placeDefineShapeTag(node, shapeRecords, node.fill, node.stroke, context, winding);
+        return po3;
+    }
+
+    protected void setPixelBenderBlendMode(PlaceObject3Tag po, BlendMode blendMode)
+    {
+        
+    }
+    
+    protected void setAlphaMask(PlaceObject3Tag po)
+    {
+        po.setHasCacheAsBitmap(true);
+    }
+    
+    protected void setLuminosityMask(PlaceObject3Tag po)
+    {
+       
+    }
+    
+    protected PlaceObject3Tag PlaceObject3Tag(ICharacterTag symbol, GraphicContext context)
+    {
+        DefineSpriteTag sprite = spriteStack.peek();
+
+        PlaceObject3Tag po3 = new PlaceObject3Tag();
+        // po3.setName(name);
+        po3.setCharacter(symbol);
+        assert symbol != sprite;
+        po3.setHasCharacter(true);
+        Integer depthCount = getSpriteDepth(sprite) + 1;
+        
+        setSpriteDepth(sprite, depthCount);
+        
+        po3.setDepth(depthCount);
+        if (context.blendMode != null)
+        {
+            if (!context.blendMode.needsPixelBenderSupport())
+            {
+                int blendMode = createBlendMode(context.blendMode);
+                po3.setBlendMode(blendMode);
+                po3.setHasBlendMode(true);
+            }
+            else
+            {
+                setPixelBenderBlendMode(po3, context.blendMode);
+            }
+        }
+        
+        if (context.filters != null)
+        {
+            List<Filter> filters = createFilters(context.filters);
+            Filter filterArray[] = {};
+            po3.setSurfaceFilterList(filters.toArray(filterArray));
+            po3.setHasFilterList(true);
+        }
+
+        // FXG angles are always clockwise.
+        Matrix matrix = context.getTransform().toSWFMatrix();
+        po3.setMatrix(matrix);
+        po3.setHasMatrix(true);
+        if (context.colorTransform != null)
+        {
+            ColorTransformNode t = context.colorTransform;
+            CXFormWithAlpha cx = TypeHelper.cxFormWithAlpha(t.alphaMultiplier, t.redMultiplier, t.greenMultiplier, t.blueMultiplier, t.alphaOffset, t.redOffset, t.greenOffset, t.blueOffset);
+            po3.setColorTransform(cx);
+            po3.setHasColorTransform(true);
+        }
+
+        
+        if (context.maskType == MaskType.ALPHA)
+        {
+            setAlphaMask(po3);
+        }
+        else if (context.maskType == MaskType.LUMINOSITY)
+        {
+            setLuminosityMask(po3);
+        }
+        sprite.getControlTags().add(po3);
+        return po3;
+    }
+
+
+    protected PlaceObject3Tag rect(RectNode node)
+    {
+        // Note that we will apply node.x and node.y as a translation operation
+        // in the PlaceObject3Tag3 Matrix and instead start the shape from the
+        // origin (0.0, 0.0).
+        GraphicContext context = node.createGraphicContext();
+        List<ShapeRecord> shapeRecords;
+        if (node.radiusX != 0.0 || node.radiusY != 0.0 
+        		|| !Double.isNaN(node.topLeftRadiusX) || !Double.isNaN(node.topLeftRadiusY)
+        		|| !Double.isNaN(node.topRightRadiusX) || !Double.isNaN(node.topRightRadiusY)
+        		|| !Double.isNaN(node.bottomLeftRadiusX) || !Double.isNaN(node.bottomLeftRadiusY)
+        		|| !Double.isNaN(node.bottomRightRadiusX) || !Double.isNaN(node.bottomRightRadiusY))
+        {
+             shapeRecords  = ShapeHelper.rectangle(0.0, 0.0, node.width, node.height, 
+            		 node.radiusX, node.radiusY, node.topLeftRadiusX, node.topLeftRadiusY,
+            		 node.topRightRadiusX, node.topRightRadiusY, node.bottomLeftRadiusX, node.bottomLeftRadiusY,
+            		 node.bottomRightRadiusX, node.bottomRightRadiusY);
+        }
+        else
+        {
+             shapeRecords = ShapeHelper.rectangle(0.0, 0.0, node.width, node.height);
+        }
+        
+        PlaceObject3Tag po3 = placeDefineShapeTag(node, shapeRecords, node.fill, node.stroke, context);
+        return po3;
+    }
+
+    protected PlaceObject3Tag text(TextGraphicNode node)
+    {
+        // No operation - text is ignored in this implementation.
+        return null;
+    }
+
+    protected PlaceObject3Tag richtext(RichTextNode node)
+    {
+        // No operation - richtext is ignored in this implementation.
+        return null;
+    }
+
+    // --------------------------------------------------------------------------
+    //
+    // FXG Library Definitions
+    //
+    // --------------------------------------------------------------------------
+
+    protected PlaceObject3Tag PlaceObject3TagInstance(PlaceObjectNode node)
+    {
+        String definitionName = node.getNodeName();
+
+        if (definitions == null)
+            definitions = new HashMap<String, DefineSpriteTag>();
+
+        DefineSpriteTag definitionSprite = definitions.get(definitionName);
+        if (definitionSprite == null)
+        {
+            definitionSprite = createDefineSpriteTag("Definition");
+            FXG2SWFTranscoder graphics = newInstance();
+            graphics.setResourceResolver(resourceResolver);
+            definitions.put(definitionName, definitionSprite);
+            graphics.definitions = definitions;
+            graphics.problems = problems;
+            graphics.definition(node.definition, definitionSprite);
+        }
+
+        PlaceObject3Tag po3 = PlaceObject3Tag(definitionSprite, node.createGraphicContext());
+        return po3;
+    }
+
+    protected void definition(DefinitionNode node, DefineSpriteTag definitionSprite)
+    {
+        GroupDefinitionNode groupDefinition = node.groupDefinition;
+        
+        if (groupDefinition == null) 
+        {
+            // Definitions must define a single Group child node.
+            problems.add(new FXGMissingGroupChildNodeProblem(node.getDocumentPath(), node.getStartLine(), 
+                    node.getStartColumn()));
+            return;
+        }
+        spriteStack.push(definitionSprite);
+        
+        if (groupDefinition.definesScaleGrid())
+        {
+            DefineScalingGridTag scalingGrid = createDefineScalingGridTag(groupDefinition.getScalingGrid());
+            scalingGrid.setCharacter(definitionSprite);
+            extraTags.put(definitionSprite,scalingGrid);
+            //definitionSprite.scalingGrid = scalingGrid;
+            
+        }
+
+        graphicContentNodes(groupDefinition.children);
+
+        spriteStack.pop();
+    }
+
+    // --------------------------------------------------------------------------
+    //
+    // SWF Tags and Types Helper Methods
+    //
+    // --------------------------------------------------------------------------
+
+    protected DefineImage createDefineBitsTag(IFXGNode node, String source)
+    {
+        DefineImage imageTag = imageMap.get(source);
+        if (imageTag == null)
+        {
+            try
+            {                
+                InputStream stream = resourceResolver.openStream(source);
+                imageTag = ImageHelper.createDefineBits(stream, ImageHelper.guessMimeType(source));
+                imageMap.put(source, imageTag);
+            }
+            catch (IOException ioe)
+            {
+                // Error {0} occurred while embedding image {1}.
+                problems.add(new FXGErrorEmbeddingImageProblem(node.getDocumentPath(), node.getStartLine(), 
+                        node.getStartColumn(), ioe.getMessage(), source));
+                return null;
+            }
+        }
+        return imageTag;
+    }
+
+    protected DefineScalingGridTag createDefineScalingGridTag(ScalingGrid grid)
+    {
+        DefineScalingGridTag scalingGrid = new DefineScalingGridTag();
+        scalingGrid.setSplitter(TypeHelper.rect(grid.scaleGridLeft, grid.scaleGridTop, grid.scaleGridRight, grid.scaleGridBottom));
+        return scalingGrid;
+    }
+
+    protected DefineSpriteTag createDefineSpriteTag(String name)
+    {
+        DefineSpriteTag sprite = new DefineSpriteTag(0, new ArrayList<ITag>());
+        if (name == null) 
+            name = "";
+        return sprite;
+    }
+ 
+    protected DefineShapeTag createDefineShapeTag(AbstractShapeNode node, List<ShapeRecord> shapeRecords, IFillNode fill,
+            IStrokeNode stroke, FXGMatrix transform, Winding... windings)
+    {
+        // Calculate the bounds of the shape outline (without strokes) - edgeBounds
+        Rect edgeBounds = (node == null) ? ShapeHelper.getBounds(shapeRecords, null, (AbstractStrokeNode)stroke) : node.getBounds(shapeRecords, null);
+        
+        
+        Rect shapeBounds;
+
+        
+        int lineStyleIndex = stroke == null ? 0 : 1;
+        int fillStyle0Index = fill == null ? 0 : 1;
+        int fillStyle1Index = 0;
+        
+        FillStyleArray fillStyles = new FillStyleArray(1);
+        LineStyleArray lineStyles = new LineStyleArray();
+        if (fill != null)
+        {
+            FillStyle fillStyle = createFillStyle(fill, edgeBounds);
+            if(fillStyle != null)
+                fillStyles.add(fillStyle);
+        }
+
+        if (stroke != null)
+        {
+        	//find the shapeBounds with stroke
+        	LineStyle ls = createGenericLineStyle((AbstractStrokeNode)stroke);
+            shapeBounds = (node == null) ? ShapeHelper.getBounds(shapeRecords, ls, (AbstractStrokeNode)stroke) : node.getBounds(shapeRecords, ls);        	
+
+            LineStyle lineStyle = createLineStyle(stroke, shapeBounds);
+            lineStyles.add(lineStyle);            
+        }
+        else
+        {
+        	shapeBounds = edgeBounds;
+        }
+
+
+        Styles styles = new Styles(fillStyles, lineStyles);
+
+
+        if (windings.length > 0)
+            ShapeHelper.setPathStyles(shapeRecords, lineStyleIndex, fillStyle0Index, fillStyle1Index, styles);
+        else
+            ShapeHelper.setStyles(shapeRecords, lineStyleIndex, fillStyle0Index, fillStyle1Index, styles);
+
+        
+        ShapeWithStyle sws = new ShapeWithStyle(styles);
+        sws.addShapeRecords(shapeRecords);
+        
+        DefineShape4Tag DefineShapeTag4 = new DefineShape4Tag();
+        DefineShapeTag4.setShapes(sws);
+        DefineShapeTag4.setShapeBounds(shapeBounds);
+        DefineShapeTag4.setEdgeBounds(edgeBounds);
+        if ((fill != null) &&( windings.length > 0))
+        {
+        	Winding windingValue = windings[0];
+            DefineShapeTag4.setUsesFillWindingRule(windingValue == Winding.NON_ZERO);
+        }
+        
+        return DefineShapeTag4;
+    }
+    
+    
+    protected PlaceObject3Tag placeDefineShapeTag(AbstractShapeNode node, List<ShapeRecord> shapeRecords, 
+            IFillNode fill, IStrokeNode stroke, GraphicContext context, Winding... windings )
+    {
+ 
+        if (node != null && fill!= null && !node.isPartofClipMask && ImageHelper.isBitmapFillWithClip(fill)) 
+        {
+            /* Support of fillMode=clip/scale is complicated since SWF does not 
+             * support proper clipping of bitmaps. For fillMode=clip/scale, FXG defines 
+             * the area outside of the bitmap fill area to be transparent.
+             * In SWF, the bitmap bleeds to fill the rest of the path/shape 
+             * if bitmap is specified to be a clipping bitmap.
+             * 
+             * In order to get the effect that FXG wants with SWF tags, the
+             * the path/shape is split into two ShapeRecords for a path 
+             * with a stroke & fill. A clipping mask is applied to the fill 
+             * but not the stroke.
+             */
+            
+            BitmapFillNode fillNode = (BitmapFillNode) fill;
+
+            // Calculate the bounds of the shape outline (without strokes)
+            Rect edgeBounds = node.getBounds(shapeRecords, null);           
+            
+            String source = parseSource(fillNode.source);
+            if (source == null)
+            {
+                // Missing source attribute in <BitmapGraphic> or <BitmapFill>.
+                problems.add(new FXGMissingAttributeProblem(node.getDocumentPath(), node.getStartLine(), 
+                        node.getStartColumn(), FXGConstants.FXG_SOURCE_ATTRIBUTE, node.getNodeName()));
+                return null;
+            }
+            DefineImage defImage = createDefineBitsTag(fill, source);
+            if(defImage == null)
+                return null;
+
+            //process the filters later to avoid masking
+            List<IFilterNode> filters = null;
+            if (context.filters != null)       
+            {   
+                filters = context.filters;
+                context.filters = null;
+                DefineSpriteTag filterSprite = createDefineSpriteTag("MaskFilter");
+                spriteStack.push(filterSprite);
+            }
+
+            DefineSpriteTag imageSprite = createDefineSpriteTag("BitmapFill");
+            spriteStack.push(imageSprite);
+            
+            // First, generate the clipping mask
+            DefineSpriteTag clipSprite = createDefineSpriteTag("BitmapFill_Clip");
+            spriteStack.push(clipSprite);
+            
+            List<ShapeRecord> clipRectRecords = ShapeHelper.rectangle(0.0, 0.0, defImage.getWidth(), defImage.getHeight());
+            DefineShapeTag clipShape = createDefineShapeTag(null, clipRectRecords, new SolidColorFillNode(), null, context.getTransform());
+            FXGMatrix bitmapMatrix = TypeHelper.bitmapFillMatrix(fillNode, defImage, edgeBounds);
+            FXGMatrix clipMatrix = new FXGMatrix(bitmapMatrix.a, bitmapMatrix.b, bitmapMatrix.c, bitmapMatrix.d, 0, 0);
+            clipMatrix.scale(1.0/ISWFConstants.TWIPS_PER_PIXEL, 1.0/ISWFConstants.TWIPS_PER_PIXEL);
+            clipMatrix.translate(bitmapMatrix.tx, bitmapMatrix.ty);
+            GraphicContext clipContext = new GraphicContext();
+            clipContext.setTransform(clipMatrix);
+            PlaceObject3Tag(clipShape, clipContext); 
+            spriteStack.pop();
+            
+            // Set the depth of the mask to that of the bitmap image fill
+            clipContext.setTransform(context.getTransform());
+            PlaceObject3Tag po3clip = PlaceObject3Tag(clipSprite, clipContext); 
+            po3clip.setClipDepth(po3clip.getDepth() + 1);
+            po3clip.setHasClipDepth(true);
+            
+            Styles styles = new Styles(new FillStyleArray(), new LineStyleArray());
+            // Then, process the bitmap image fill
+            ShapeWithStyle sws = new ShapeWithStyle(styles);
+            
+            int lineStyleIndex = 0;
+            int fillStyle0Index = 1;
+            int fillStyle1Index = 0;
+
+            FillStyle fillStyle = createFillStyle(fill, edgeBounds);
+            if(fillStyle != null)
+                sws.getFillStyles().add(fillStyle);
+
+            if (windings.length > 0)
+                ShapeHelper.setPathStyles(shapeRecords, lineStyleIndex, fillStyle0Index, fillStyle1Index, styles);
+            else
+                ShapeHelper.setStyles(shapeRecords, lineStyleIndex, fillStyle0Index, fillStyle1Index, styles);
+            
+            sws.addShapeRecords(shapeRecords);
+            
+            DefineShape4Tag imageShape = new DefineShape4Tag();
+            imageShape.setShapes(sws);
+            imageShape.setShapeBounds(edgeBounds);
+            imageShape.setEdgeBounds(edgeBounds);
+            if ((fill != null) &&( windings.length > 0))
+            {
+                Winding windingValue = windings[0];
+                imageShape.setUsesFillWindingRule(windingValue == Winding.NON_ZERO);
+            }
+            PlaceObject3Tag po3 = PlaceObject3Tag(imageShape, context);        
+             
+            if (stroke != null)
+            {
+                //make a copy of ShapeRecord for strokes
+                ArrayList<ShapeRecord> shapeRecords2 = new ArrayList<ShapeRecord>(shapeRecords);
+                Collections.copy(shapeRecords2, shapeRecords);
+
+                Styles strokeStyles = new Styles(new FillStyleArray(), new LineStyleArray());
+
+                //generate the define sprite for the stroke object with no clipping
+                ShapeWithStyle swsStroke = new ShapeWithStyle(strokeStyles);
+
+                // Consider linestyle stroke widths with bounds calculation               
+                AbstractStrokeNode strokeNode = (AbstractStrokeNode) stroke;
+                LineStyle ls = createGenericLineStyle(strokeNode);
+                Rect shapeBounds =  node.getBounds(shapeRecords2, ls);     
+                
+                LineStyle lineStyle = createLineStyle(stroke, shapeBounds);
+                swsStroke.getLineStyles().add(lineStyle);
+                
+                lineStyleIndex = 1;
+                fillStyle0Index = 0;
+                fillStyle1Index = 0;
+                ShapeHelper.replaceStyles(shapeRecords2, lineStyleIndex, fillStyle0Index, fillStyle1Index, strokeStyles);
+         
+                swsStroke.addShapeRecords(shapeRecords2);
+
+                DefineShape4Tag strokeShape = new DefineShape4Tag();
+                strokeShape.setShapes(swsStroke);
+                strokeShape.setShapeBounds(shapeBounds);
+                strokeShape.setEdgeBounds(edgeBounds);
+                po3 = PlaceObject3Tag(strokeShape, context);    
+            }             
+            spriteStack.pop();
+            
+            po3 = PlaceObject3Tag(imageSprite, new GraphicContext());
+            
+            // If filters were not processed, place the topmost sprite in display list and apply filters 
+            // This is done to force processing of masks before filters
+            if (filters != null)
+            {
+                DefineSpriteTag sprite = spriteStack.pop();
+                
+                GraphicContext gc = new GraphicContext();
+                gc.filters = filters;
+                PlaceObject3Tag poFilter = PlaceObject3Tag(sprite, gc);
+                return poFilter;            
+            }
+            
+            return po3;
+            
+        }
+        else
+        {
+        	DefineShapeTag shape = createDefineShapeTag(node, shapeRecords, fill, stroke, context.getTransform(), windings);
+        	PlaceObject3Tag po3 = PlaceObject3Tag(shape, context);
+        	return po3;
+        } 
+       
+    }
+    
+    protected FillStyle createFillStyle(IFillNode fill, Rect bounds)
+     {
+        if (fill instanceof SolidColorFillNode)
+            return createFillStyle((SolidColorFillNode)fill);
+        else if (fill instanceof LinearGradientFillNode)
+            return createFillStyle((LinearGradientFillNode)fill, bounds);
+        else if (fill instanceof RadialGradientFillNode)
+            return createFillStyle((RadialGradientFillNode)fill, bounds);
+        else if (fill instanceof BitmapFillNode)
+            return createFillStyle((BitmapFillNode)fill, bounds);
+        else
+            return null;
+    }
+
+    protected FillStyle createFillStyle(SolidColorFillNode fill)
+    {
+        FillStyle fs = new FillStyle();
+        fs.setColor(TypeHelper.splitColor(TypeHelper.colorARGB(fill.color, fill.alpha)));
+        fs.setFillStyleType(FillStyle.SOLID_FILL);
+        return fs;
+    }
+
+    protected FillStyle createFillStyle(BitmapFillNode fill, Rect bounds)
+    {
+        FillStyle fs = new FillStyle();
+        
+        if (ImageHelper.bitmapFillModeIsRepeat(fill))
+            fs.setFillStyleType(FillStyle.REPEATING_BITMAP_FILL);
+        else
+            fs.setFillStyleType(FillStyle.CLIPPED_BITMAP_FILL);
+
+        String sourceFormatted = parseSource(fill.source);
+        
+        if (sourceFormatted == null)
+        {
+            // Source is required after FXG 1.0
+            // Missing source attribute in <BitmapGraphic> or <BitmapFill>.
+            problems.add(new FXGMissingAttributeProblem(fill.getDocumentPath(), fill.getStartLine(), 
+                    fill.getStartColumn(), FXGConstants.FXG_SOURCE_ATTRIBUTE, fill.getNodeName()));
+            return null;
+        }
+
+        DefineImage img = createDefineBitsTag(fill, sourceFormatted); 
+        if(img != null)
+        {
+            fs.setBitmapCharacter(img.getTag());
+        
+            fs.setBitmapMatrix(TypeHelper.bitmapFillMatrix(fill, img, bounds).toSWFMatrix());
+        }
+        return fs;
+    }
+
+    protected FillStyle createFillStyle(LinearGradientFillNode node, Rect bounds)
+    {
+        FillStyle fs = new FillStyle();
+        fs.setFillStyleType(FillStyle.LINEAR_GRADIENT_FILL);
+        fs.setGradientMatrix(TypeHelper.linearGradientMatrix(node, bounds));
+        Gradient gradient = new Gradient();
+        populateGradient(gradient, node.entries, node.interpolationMethod, node.spreadMethod);
+        fs.setGradient(gradient);
+
+        return fs;
+    }
+
+    protected FillStyle createFillStyle(LinearGradientStrokeNode node, Rect bounds)
+    {
+        FillStyle fs = new FillStyle();
+        fs.setFillStyleType(FillStyle.LINEAR_GRADIENT_FILL);
+        fs.setGradientMatrix(TypeHelper.linearGradientMatrix(node, bounds));
+        Gradient gradient = new Gradient();
+        populateGradient(gradient, node.entries, node.interpolationMethod, node.spreadMethod);
+        fs.setGradient(gradient);
+
+        return fs;
+    }
+
+    protected FillStyle createFillStyle(RadialGradientFillNode node, Rect bounds)
+    {
+        FillStyle fs = new FillStyle();
+        fs.setFillStyleType(FillStyle.FOCAL_RADIAL_GRADIENT_FILL);
+        fs.setGradientMatrix(TypeHelper.radialGradientMatrix(node, bounds));
+        FocalGradient gradient = new FocalGradient();
+        populateGradient(gradient, node.entries, node.interpolationMethod, node.spreadMethod);
+        gradient.setFocalPoint((float)node.focalPointRatio);
+        fs.setGradient(gradient);
+
+        return fs;
+    }
+
+    protected FillStyle createFillStyle(RadialGradientStrokeNode node, Rect bounds)
+    {
+        FillStyle fs = new FillStyle();
+        fs.setFillStyleType(FillStyle.FOCAL_RADIAL_GRADIENT_FILL);
+        fs.setGradientMatrix(TypeHelper.radialGradientMatrix(node, bounds));
+        FocalGradient gradient = new FocalGradient();
+        populateGradient(gradient, node.entries, node.interpolationMethod, node.spreadMethod);
+        gradient.setFocalPoint((float)node.focalPointRatio);
+        fs.setGradient(gradient);
+
+        return fs;
+    }
+    
+    protected LineStyle createLineStyle(IStrokeNode stroke, Rect bounds)
+    {
+        if (stroke instanceof SolidColorStrokeNode)
+            return createLineStyle((SolidColorStrokeNode)stroke);
+        else if (stroke instanceof LinearGradientStrokeNode)
+            return createLineStyle((LinearGradientStrokeNode)stroke, bounds);
+        else if (stroke instanceof RadialGradientStrokeNode)
+            return createLineStyle((RadialGradientStrokeNode)stroke, bounds);
+        else
+            return null;
+    }
+
+    private LineStyle2 createGenericLineStyle(AbstractStrokeNode stroke)
+    {
+        LineStyle2 ls = new LineStyle2();
+        ls.setWidth((int)StrictMath.rint(stroke.getWeight() * ISWFConstants.TWIPS_PER_PIXEL));
+
+        int startCapStyle = createCaps(stroke.caps);
+        int endCapStyle = startCapStyle;
+        int jointStyle = createJoints(stroke.joints);
+        
+        boolean noHScaleFlag = stroke.scaleMode == ScaleMode.VERTICAL || stroke.scaleMode == ScaleMode.NONE;
+        boolean noVScaleFlag = stroke.scaleMode == ScaleMode.HORIZONTAL || stroke.scaleMode == ScaleMode.NONE;
+        
+        // The 4.5.1 Flex Compiler switches these two flags.                   
+        // A bug has been logged in JIRA against the old compiler for this issue
+        // http://bugs.adobe.com/jira/browse/SDK-31114
+        ls.setNoHScaleFlag(noHScaleFlag);
+        ls.setNoVScaleFlag(noVScaleFlag);
+        
+        ls.setJoinStyle(jointStyle);
+        ls.setStartCapStyle(startCapStyle);
+        ls.setEndCapStyle(endCapStyle);
+        ls.setPixelHintingFlag(stroke.pixelHinting);
+        
+        if (jointStyle == 2)
+        {
+            // Encoded in SWF as an 8.8 fixed point value
+            ls.setMiterLimitFactor((float)(stroke.miterLimit));
+        }
+        
+        return ls;
+    }
+    protected LineStyle createLineStyle(SolidColorStrokeNode stroke)
+    {
+        LineStyle ls = createGenericLineStyle(stroke);
+        ls.setColor(TypeHelper.splitColor(TypeHelper.colorARGB(stroke.color, stroke.alpha)));
+        return ls;
+    }
+    
+    protected LineStyle2 createLineStyle(LinearGradientStrokeNode stroke, Rect bounds)
+    {
+        LineStyle2 ls = createGenericLineStyle(stroke);
+        ls.setFillType(createFillStyle(stroke, bounds));
+        ls.setHasFillFlag(true);
+        return ls;
+    }
+
+    protected LineStyle2 createLineStyle(RadialGradientStrokeNode stroke, Rect edgeBounds)
+    {
+        LineStyle2 ls = createGenericLineStyle(stroke);
+        ls.setFillType(createFillStyle(stroke, edgeBounds));
+        ls.setHasFillFlag(true);
+        return ls;
+    }
+
+    protected int createCaps(Caps value)
+    {
+        if (value != null)
+            return value.ordinal();
+        else
+            return Caps.NONE.ordinal();
+    }
+
+    protected int createJoints(Joints value)
+    {
+        if (value != null)
+            return value.ordinal();
+        else
+            return Joints.ROUND.ordinal();
+    }
+
+    protected int createSpreadMode(SpreadMethod value)
+    {
+        return value.ordinal();
+    }
+
+    protected int createBlendMode(BlendMode value)
+    {
+        return value.ordinal();
+    }
+
+    protected int createInterpolationMode(InterpolationMethod value)
+    {
+        return value.ordinal();
+    }
+
+    protected List<Filter> createFilters(List<IFilterNode> list)
+    {
+        List<Filter> filters = new ArrayList<Filter>(list.size());
+        Iterator<IFilterNode> iterator = list.iterator();
+        while (iterator.hasNext())
+        {
+            IFilterNode f = iterator.next();
+            if (f instanceof BevelFilterNode)
+            {
+                BevelFilterNode node = (BevelFilterNode)f;
+                BevelFilter filter = createBevelFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.BEVEL);
+                rec.setBevelFilter(filter);
+                filters.add(rec);
+            }
+            else if (f instanceof BlurFilterNode)
+            {
+                BlurFilterNode node = (BlurFilterNode)f;
+                BlurFilter filter = createBlurFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.BLUR);
+                rec.setBlurFilter(filter);
+                filters.add(rec);
+            }
+            else if (f instanceof ColorMatrixFilterNode)
+            {
+                ColorMatrixFilterNode node = (ColorMatrixFilterNode)f;
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.COLOR_MATRIX);
+                rec.setColorMatrixFilter(node.matrix);
+                filters.add(rec);
+            }
+            else if (f instanceof DropShadowFilterNode)
+            {
+                DropShadowFilterNode node = (DropShadowFilterNode)f;
+                DropShadowFilter filter = createDropShadowFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.DROP_SHADOW);
+                rec.setDropShadowFilter(filter);
+                filters.add(rec);
+            }
+            else if (f instanceof GlowFilterNode)
+            {
+                GlowFilterNode node = (GlowFilterNode)f;
+                GlowFilter filter = createGlowFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.GLOW);
+                rec.setGlowFilter(filter);
+                filters.add(rec);
+            }
+            else if (f instanceof GradientBevelFilterNode)
+            {
+                GradientBevelFilterNode node = (GradientBevelFilterNode)f;
+                GradientBevelFilter filter = createGradientBevelFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.GRADIENT_BEVEL);
+                rec.setGradientBevelFilter(filter);
+                filters.add(rec);
+            }
+            else if (f instanceof GradientGlowFilterNode)
+            {
+                GradientGlowFilterNode node = (GradientGlowFilterNode)f;
+                GradientGlowFilter filter = createGradientGlowFilter(node);
+                Filter rec = new Filter();
+                rec.setFilterID(Filter.GRADIENT_GLOW);
+                rec.setGradientGlowFilter(filter);
+                filters.add(rec);
+            }
+        }
+        return filters;
+    }
+
+    protected BevelFilter createBevelFilter(BevelFilterNode node)
+    {
+        BevelFilter filter = new BevelFilter();
+        filter.setAngle((float)(node.angle*Math.PI/180.0));
+        filter.setBlurX((float)node.blurX);
+        filter.setBlurY((float)node.blurY);
+        filter.setDistance((float)node.distance);
+        filter.setStrength((float)node.strength);
+        filter.setShadowColor(TypeHelper.splitColor(TypeHelper.colorARGB(node.shadowColor, node.shadowAlpha)));
+        filter.setHighlightColor(TypeHelper.splitColor(TypeHelper.colorARGB(node.highlightColor, node.highlightAlpha)));
+        
+        
+        filter.setOnTop(node.type == BevelType.FULL);
+        
+        filter.setInnerShadow(node.type == BevelType.INNER);
+        filter.setPasses(node.quality);
+        filter.setKnockout(node.knockout);
+        filter.setCompositeSource(true);
+        return filter;
+    }
+
+    protected BlurFilter createBlurFilter(BlurFilterNode node)
+    {
+        BlurFilter filter = new BlurFilter();
+        filter.setBlurX((float)(node.blurX));
+        filter.setBlurY((float)(node.blurY));
+        filter.setPasses(node.quality);
+        return filter;
+    }
+
+    protected DropShadowFilter createDropShadowFilter(DropShadowFilterNode node)
+    {
+        DropShadowFilter filter = new DropShadowFilter();
+        filter.setDropShadowColor(TypeHelper.splitColor(TypeHelper.colorARGB(node.color, node.alpha)));
+        filter.setAngle((float)(node.angle*Math.PI/180.0));
+        filter.setBlurX((float)(node.blurX));
+        filter.setBlurY((float)(node.blurY));
+        filter.setDistance((float)(node.distance));
+        filter.setStrength((float)(node.strength));
+        filter.setPasses(node.quality);
+        filter.setCompositeSource(!node.hideObject);
+        filter.setKnockout(node.knockout);
+        filter.setInnerShadow(node.inner);
+        return filter;
+    }
+
+    protected GlowFilter createGlowFilter(GlowFilterNode node)
+    {
+        GlowFilter filter = new GlowFilter();
+        filter.setGlowColor(TypeHelper.splitColor(TypeHelper.colorARGB(node.color, node.alpha)));
+        filter.setBlurX((float)(node.blurX));
+        filter.setBlurY((float)(node.blurY));
+        filter.setStrength((float)(node.strength));
+        filter.setKnockout(node.knockout);
+        filter.setInnerGlow(node.inner);
+        filter.setCompositeSource(true);
+        filter.setPasses(node.quality);
+        
+        return filter;
+    }
+
+    protected GradientBevelFilter createGradientBevelFilter(
+            GradientBevelFilterNode node)
+    {
+        GradientBevelFilter filter = new GradientBevelFilter();
+        if (node.entries != null)
+        {
+            byte count = (byte)node.entries.size();
+            filter.setNumColors(count);
+            RGBA gradientColors[] = new RGBA[count];
+            int gradientRatios[] = new int[count];
+            filter.setGradientColors(gradientColors);
+            filter.setGradientRatio(gradientRatios);
+
+            GradRecord[] records = createGradRecords(node.entries);
+            for (int i = 0; i < records.length; i++)
+            {
+                GradRecord record = records[i];
+                RGB color = record.getColor();
+                if (color instanceof RGBA)
+                    gradientColors[i] = (RGBA)color;
+                else
+                    gradientColors[i] = new RGBA(color.getRed(), color.getGreen(), color.getBlue(), 0xFF);
+                gradientRatios[i] = record.getRatio();
+            }
+        }
+
+        filter.setAngle((float)(node.angle*Math.PI/180.0));
+        filter.setBlurX((float)(node.blurX));
+        filter.setBlurY((float)(node.blurY));
+        filter.setDistance((float)(node.distance));
+        filter.setStrength((float)(node.strength));
+        filter.setKnockout(node.knockout);
+        filter.setPasses(node.quality);
+        filter.setCompositeSource(true);
+        filter.setInnerShadow(node.type == BevelType.INNER);
+        filter.setOnTop(node.type == BevelType.FULL);
+
+        return filter;
+    }
+
+    protected GradientGlowFilter createGradientGlowFilter(
+            GradientGlowFilterNode node)
+    {
+        GradientGlowFilter filter = new GradientGlowFilter();
+
+        if (node.entries != null)
+        {
+            byte count = (byte)node.entries.size();
+            filter.setNumColors(count);
+            RGBA gradientColors[] = new RGBA[count];
+            int gradientRatio[] = new int[count];
+
+            GradRecord[] records = createGradRecords(node.entries);
+            for (int i = 0; i < records.length; i++)
+            {
+                GradRecord record = records[i];
+                RGB color = record.getColor();
+                if (color instanceof RGBA)
+                    gradientColors[i] = (RGBA)color;
+                else
+                    gradientColors[i] = new RGBA(color.getRed(), color.getGreen(), color.getBlue(), 0xFF);
+                gradientRatio[i] = record.getRatio();
+            }
+            filter.setGradientColors(gradientColors);
+            filter.setGradientRatio(gradientRatio);
+        }
+
+        filter.setAngle((float)(node.angle*Math.PI/180.0));
+        filter.setBlurX((float)node.blurX);
+        filter.setBlurY((float)node.blurY);
+        filter.setDistance((float)node.distance);
+        filter.setStrength((float)node.strength);
+        
+        filter.setPasses(node.quality);
+        filter.setKnockout(node.knockout);
+        filter.setInnerGlow(node.inner);
+        filter.setCompositeSource(true);
+
+        return filter;
+    }
+
+    protected void populateGradient(Gradient gradient,
+            List<GradientEntryNode> entries, InterpolationMethod interpolation,
+            SpreadMethod spread)
+    {
+        gradient.setGradientRecords(Arrays.asList(createGradRecords(entries)));
+
+        if (interpolation != null)
+            gradient.setInterpolationMode(createInterpolationMode(interpolation));
+
+        if (spread != null)
+            gradient.setSpreadMode(createSpreadMode(spread));
+    }
+
+    protected GradRecord[] createGradRecords(List<GradientEntryNode> entries)
+    {
+        int count = entries.size();
+        GradRecord[] records = new GradRecord[count];
+        double previousRatio = 0.0;
+        for (int currentIndex = 0; currentIndex < count; currentIndex++)
+        {
+            GradientEntryNode entry = entries.get(currentIndex);
+            double thisRatio = entry.ratio;
+
+            // Auto-calculate gradient ratio if omitted from an entry.
+            if (Double.isNaN(thisRatio))
+            {
+                // The first ratio is assumed to be 0.0.
+                if (currentIndex == 0)
+                {
+                    thisRatio = 0.0;
+                }
+                // The last ratio is assumed to be 1.0.
+                else if (currentIndex == count - 1)
+                {
+                    thisRatio = 1.0;
+                }
+                else
+                {
+                    // Other omitted ratios are divided evenly between the last
+                    // ratio and the next specified ratio (or 1.0 if none).
+                    double nextRatio = 1.0;
+                    int nextIndex = count - 1;
+                    for (int i = currentIndex; i < count; i++)
+                    {
+                        GradientEntryNode nextEntry = entries.get(i);
+                        if (!Double.isNaN(nextEntry.ratio))
+                        {
+                            nextRatio = nextEntry.ratio;
+                            nextIndex = i;
+                            break;
+                        }
+                    }
+
+                    int entryGap = nextIndex - (currentIndex - 1);
+                    if (entryGap > 0)
+                    {
+                        thisRatio = previousRatio + ((nextRatio - previousRatio) / (entryGap));
+                    }
+                    else
+                    {
+                        thisRatio = previousRatio;
+                    }
+                }
+            }
+
+            GradRecord record = new GradRecord(TypeHelper.gradientRatio(thisRatio), TypeHelper.splitColor(TypeHelper.colorARGB(entry.color, entry.alpha)));
+            records[currentIndex] = record;
+
+            // Remember this ratio as the last one specified
+            previousRatio = thisRatio;
+        }
+
+        return records;
+    }
+
+    protected String parseSource(String source)
+    {
+        // TODO: Create a standard @Embed() parser.
+        if (source != null)
+        {
+            source = source.trim();
+
+            if (source.startsWith("@Embed("))
+            {
+                source = source.substring(7).trim();
+
+                if (source.endsWith(")"))
+                {
+                    source = source.substring(0, source.length() - 1).trim();
+                }
+
+                if (source.charAt(0) == '\'' && source.charAt(source.length() - 1) == '\'')
+                {
+                    source = source.substring(1, source.length() - 1).trim();
+                }
+            }
+        }
+
+        return source;
+    }
+    
+    private void  markLeafNodesAsMask(IMaskableNode maskableNode, GroupNode mask)
+    {
+        if ((mask == null) || (mask.children == null))
+            return;
+    	Iterator<GraphicContentNode> iter = mask.children.iterator();
+    	while (iter.hasNext()) 
+    	{
+    		GraphicContentNode gcNode = iter.next();
+    		if (gcNode instanceof GroupNode)
+    		{
+    			markLeafNodesAsMask(maskableNode, (GroupNode) gcNode);
+    		}
+    		else
+    		{
+     		    if (maskableNode.getMaskType() == MaskType.CLIP)
+    		        gcNode.isPartofClipMask = true; 
+    		}
+    	}
+    }
+
+    @Override
+    public ITypeDefinition[] getDependencies()
+    {
+        return new ITypeDefinition[0];
+    }
+    
+    /**
+     * This class wraps a PathIterator and adds a IShapeIterator
+     * implemenation.
+     */
+    private static class PathIteratorWrapper implements IShapeIterator
+    {
+        private PathIterator pi;
+
+        public PathIteratorWrapper(PathIterator pi)
+        {
+            this.pi = pi;
+        }
+
+        @Override
+        public short currentSegment(double[] coords)
+        {
+            int code = pi.currentSegment(coords);
+            return (short) code;
+        }
+
+        @Override
+        public boolean isDone()
+        {
+            return pi.isDone();
+        }
+
+        @Override
+        public void next()
+        {
+            pi.next();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/compiler/internal/abc/ABCScopeBuilder.java
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/compiler/internal/abc/ABCScopeBuilder.java b/compiler/src/main/java/org/apache/flex/compiler/internal/abc/ABCScopeBuilder.java
new file mode 100644
index 0000000..303f614
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/compiler/internal/abc/ABCScopeBuilder.java
@@ -0,0 +1,421 @@
+/*
+ *
+ *  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.abc;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.flex.abc.ABCConstants;
+import org.apache.flex.abc.ABCParser;
+import org.apache.flex.abc.semantics.ClassInfo;
+import org.apache.flex.abc.semantics.InstanceInfo;
+import org.apache.flex.abc.semantics.MethodInfo;
+import org.apache.flex.abc.semantics.Name;
+import org.apache.flex.abc.semantics.Namespace;
+import org.apache.flex.abc.semantics.Nsset;
+import org.apache.flex.abc.semantics.PooledValue;
+import org.apache.flex.abc.visitors.IClassVisitor;
+import org.apache.flex.abc.visitors.IMethodVisitor;
+import org.apache.flex.abc.visitors.IScriptVisitor;
+import org.apache.flex.abc.visitors.NilABCVisitor;
+import org.apache.flex.compiler.constants.IASLanguageConstants;
+import org.apache.flex.compiler.definitions.INamespaceDefinition;
+import org.apache.flex.compiler.definitions.references.INamespaceReference;
+import org.apache.flex.compiler.definitions.references.IReference;
+import org.apache.flex.compiler.definitions.references.ReferenceFactory;
+import org.apache.flex.compiler.internal.definitions.ClassDefinition;
+import org.apache.flex.compiler.internal.definitions.FunctionDefinition;
+import org.apache.flex.compiler.internal.definitions.InterfaceDefinition;
+import org.apache.flex.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.flex.compiler.internal.definitions.ParameterDefinition;
+import org.apache.flex.compiler.internal.definitions.TypeDefinitionBase;
+import org.apache.flex.compiler.internal.scopes.ASFileScope;
+import org.apache.flex.compiler.internal.workspaces.Workspace;
+import org.apache.flex.compiler.scopes.IASScope;
+import org.apache.flex.compiler.scopes.IFileScopeProvider;
+import org.apache.flex.compiler.workspaces.IWorkspace;
+
+/**
+ * Populates symbol table from an ABC file.
+ */
+public class ABCScopeBuilder extends NilABCVisitor
+{
+    private static final IReference TYPE_ANY = ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.ANY_TYPE); 
+    private static final IReference TYPE_FUNCTION = ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.FUNCTION);
+
+    IReference getReference(Name name)
+    {
+        if( name == null )
+            return null;
+
+        IReference ref = nameMap.get(name);
+        if( ref != null )
+            return ref;
+
+        switch( name.getKind() )
+        {
+            case ABCConstants.CONSTANT_Qname:
+                INamespaceDefinition ns = getNamespaceReferenceForNamespace(name.getSingleQualifier());
+                ref = ReferenceFactory.resolvedQualifierQualifiedReference(workspace, ns, name.getBaseName());
+                break;
+            case ABCConstants.CONSTANT_Multiname:
+                Nsset set = name.getQualifiers();
+                if (set.length() != 1)
+                {
+                    Set<INamespaceDefinition> ns_set = new HashSet<INamespaceDefinition>(set.length());
+                    for( Namespace n : set )
+                        ns_set.add(getNamespaceReferenceForNamespace(n));
+                    ref = ReferenceFactory.multinameReference(workspace, ns_set, name.getBaseName());
+                }
+                else
+                {
+                    INamespaceDefinition singleNS = getNamespaceReferenceForNamespace(name.getSingleQualifier());
+                    ref = ReferenceFactory.resolvedQualifierQualifiedReference(workspace, singleNS, name.getBaseName());
+                }
+                break;
+            case ABCConstants.CONSTANT_TypeName:
+                // If we ever support more than Vector, we'll need to harden this code against loops
+                // in the type name's.
+                assert name.getTypeNameBase().getBaseName().equals("Vector") : "Vector is currently the only supported parameterized type!";
+                IReference parameterizedTypeReference = getReference(name.getTypeNameBase());
+                IReference parameterTypeReference = getReference(name.getTypeNameParameter());
+                ref = ReferenceFactory.parameterizedReference(workspace, parameterizedTypeReference, parameterTypeReference);
+                break;
+            default:
+                assert false : "Unsupported multiname type: " + name.getKind();
+        }
+        nameMap.put(name, ref);
+        return ref;
+    }
+    /**
+     * Encode a {@link Name} that refers to a global AS3 definition as a string.
+     * If the number of qualifiers in the {@link Name} is greater than one this
+     * method will use the first qualifier that is either of type
+     * {@link ABCConstants#CONSTANT_PackageNs} or
+     * {@link ABCConstants#CONSTANT_PackageInternalNs}.
+     * 
+     * @param name {@link Name} to encode in a String.
+     * @return A String that attempts to encode the specified {@link Name}.
+     */
+    static String getQName(Name name)
+    {
+        if (name == null)
+            return null;
+
+        String baseName = name.getBaseName();
+
+        // Look through the multiname set for a package name.
+        // TODO Although most names in SWCs seem to have only
+        // one namespace in their namespace set, interfaces seem
+        // to have true multinames with multiple namespaces.
+        // For now, just look for the package namespace.
+        // Eventually we have to deal with a real multiname.
+        String packageName = null;
+        Nsset qualifiers = name.getQualifiers();
+        if (qualifiers != null)
+        {
+            for (Namespace namespace : qualifiers)
+            {
+                if ((namespace.getKind() == ABCConstants.CONSTANT_PackageNs) || (namespace.getKind() == ABCConstants.CONSTANT_PackageInternalNs))
+                {
+                    packageName = namespace.getName();
+                    if (packageName.length() > 0)
+                        break;
+                }
+            }
+        }
+
+        return packageName != null && packageName.length() > 0 ?
+                packageName + '.' + baseName :
+                baseName;
+    }
+
+    private IReference[] getReferences(Name[] names)
+    {
+        IReference[] refs = null;
+        int n = names.length;
+        if (n != 0)
+        {
+            refs = new IReference[n];
+            for (int i = 0; i < n; i++)
+            {
+                refs[i] = getReference(names[i]);
+            }
+        }
+        return refs;
+    }
+
+    /**
+     * Create an ABCScopeBuilder from ABC byte code data.
+     * 
+     * @param workspace workspace
+     * @param abcData ABC byte code data.
+     * @param path path of the file that contains the abc data.
+     * @param fileScopeProvider callback that creates {@code ASFileScope}
+     * objects.
+     */
+    public ABCScopeBuilder(final IWorkspace workspace,
+                           final byte[] abcData,
+                           final String path,
+                           final IFileScopeProvider fileScopeProvider)
+    {
+        checkNotNull(workspace, "Workspace can't be null.");
+        checkNotNull(abcData, "ABC data can't be null.");
+        checkNotNull(path, "File path can't be null.");
+        checkNotNull(fileScopeProvider, "File scope provider can't be null.");
+
+        scopes = new ArrayList<IASScope>();
+        classDefinitions = new HashMap<ClassInfo, TypeDefinitionBase>();
+        abcParser = new ABCParser(abcData);
+        namespacesMap = new HashMap<Namespace, INamespaceDefinition>();
+        nameMap = new HashMap<Name, IReference>();
+        this.workspace = workspace;
+        this.path = path;
+        this.fileScopeProvider = fileScopeProvider;
+    }
+
+    private final IFileScopeProvider fileScopeProvider;
+    private final ABCParser abcParser;
+    private final List<IASScope> scopes;
+
+    // This is the class definition pool.
+    protected final Map<ClassInfo, TypeDefinitionBase> classDefinitions;
+
+    private final Map<Namespace, INamespaceDefinition> namespacesMap;
+
+    private final Map<Name, IReference> nameMap;
+
+    private final IWorkspace workspace;
+
+    /**
+     * Path of the file that contains the abc data. This field is used to set
+     * the containing file path of the definitions built from ABC.
+     */
+    protected final String path;
+
+    /**
+     * Constructs or otherwise obtains an {@link INamespaceReference} for an
+     * {@link Namespace}.
+     * 
+     * @param ns {@link Namespace} for which an {@link INamespaceReference}
+     * should be obtained.
+     * @return A {@link INamespaceReference} that wraps the specified
+     * {@link Namespace}.
+     */
+    public INamespaceDefinition getNamespaceReferenceForNamespace(Namespace ns)
+    {
+        INamespaceDefinition result = namespacesMap.get(ns);
+        if (result != null)
+            return result;
+
+        // Strip off versioning information.
+        Namespace nonVersionedNS = ns.getApiVersion() == ABCConstants.NO_API_VERSION?
+            ns :
+            new Namespace(ns.getKind(), ns.getName());
+        ;
+
+        result = NamespaceDefinition.createNamespaceDefinition(nonVersionedNS);
+
+        assert result != null;
+        namespacesMap.put(ns, result);
+        return result;
+    }
+
+    /**
+     * Build scopes and symbol tables from ABC.
+     * 
+     * @return the script definition object
+     * @throws IOException error
+     */
+    public List<IASScope> build() throws IOException
+    {
+        abcParser.parseABC(this);
+        return this.scopes;
+    }
+
+    @Override
+    public IScriptVisitor visitScript()
+    {
+        final ASFileScope fileScope = this.fileScopeProvider.createFileScope(workspace, path);
+        assert fileScope != null : "IFileScopeProvider shouldn't create null objects.";
+        scopes.add(fileScope);
+        return new ScriptDefinitionBuilder(this, fileScope);
+    }
+
+    /**
+     * Visit class definition pool. Build a local map from classInfo to
+     * ClassDefinition. The pool is queried by children visitors.
+     * <p>
+     * <b>InstanceInfo.Flags</b>
+     * <ul>
+     * <li>ClassSealed=0x01</li>
+     * <li>ClassFinal=0x02</li>
+     * <li>ClassInterface=0x04</li>
+     * <li>ClassProtectedNs=0x08</li>
+     * </ul>
+     */
+    @Override
+    public IClassVisitor visitClass(InstanceInfo iinfo, ClassInfo cinfo)
+    {
+        // Instance flags
+        final boolean isSealed = (iinfo.flags & ABCConstants.CONSTANT_ClassSealed) != 0;
+        final boolean isFinal = (iinfo.flags & ABCConstants.CONSTANT_ClassFinal) != 0;
+        final boolean isInterface = (iinfo.flags & ABCConstants.CONSTANT_ClassInterface) != 0;
+
+        assert iinfo.name.getKind() == ABCConstants.CONSTANT_Qname;
+        String typeName = iinfo.name.getBaseName();
+
+        final Namespace namespace = iinfo.name.getSingleQualifier();
+        final String namespaceName = namespace.getName();
+        final int namespaceKind = namespace.getKind();
+        INamespaceReference namespaceRef = null;
+        if (namespaceName.length() != 0 &&
+            ((namespaceKind == ABCConstants.CONSTANT_PackageNs) || (namespaceKind == ABCConstants.CONSTANT_PackageInternalNs)))
+        {
+            namespaceRef = 
+                ((Workspace)workspace).getPackageNamespaceDefinitionCache().get(namespaceName, namespaceKind == ABCConstants.CONSTANT_PackageInternalNs);
+        }
+        else
+        {
+            namespaceRef = NamespaceDefinition.createNamespaceDefinition(namespace);
+        }
+
+        final TypeDefinitionBase typeDefinition;
+        if (isInterface)
+        {
+            final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(typeName);
+
+            final IReference[] extendedInterfaces = getReferences(iinfo.interfaceNames);
+            interfaceDefinition.setExtendedInterfaceReferences(extendedInterfaces);
+
+            setupCastFunction(iinfo, interfaceDefinition);
+
+            typeDefinition = interfaceDefinition;
+        }
+        else
+        {
+            String protectedNSURI;
+            if (iinfo.hasProtectedNs())
+                protectedNSURI = iinfo.protectedNs.getName();
+            else
+            {
+                String classNSURI = namespace.getName();
+                protectedNSURI = (classNSURI.isEmpty() ? "" : classNSURI + ":") + typeName;
+            }
+            NamespaceDefinition.IProtectedNamespaceDefinition protectedNSDefinition = NamespaceDefinition.createProtectedNamespaceDefinition(protectedNSURI);
+            
+            final ClassDefinition classDefinition = new ClassDefinition(typeName, namespaceRef, protectedNSDefinition);
+            final IReference baseClass = getReference(iinfo.superName);
+            classDefinition.setBaseClassReference(baseClass);
+
+            final IReference[] implementedInterfaces = getReferences(iinfo.interfaceNames);
+            classDefinition.setImplementedInterfaceReferences(implementedInterfaces);
+
+            setupConstructor(iinfo, classDefinition);
+
+            typeDefinition = classDefinition;
+        }
+
+        
+        final INamespaceDefinition namespaceReference = getNamespaceReferenceForNamespace(namespace);
+        
+        typeDefinition.setNamespaceReference((INamespaceReference)namespaceReference);
+
+        if (!isSealed)
+            typeDefinition.setDynamic();
+        if (isFinal)
+            typeDefinition.setFinal();
+
+        final TypeDefinitionBuilder visitor = new TypeDefinitionBuilder(this, typeDefinition);
+
+        classDefinitions.put(cinfo, typeDefinition);
+
+        return visitor;
+    }
+
+    @Override
+    public IMethodVisitor visitMethod(MethodInfo minfo)
+    {
+        return null;
+    }
+
+    private void setupConstructor(InstanceInfo iinfo, ClassDefinition classDefinition)
+    {
+        String ctorName = ScopedDefinitionTraitsVisitor.getDefinitionName(iinfo.name);
+
+        FunctionDefinition ctor = new FunctionDefinition(ctorName);
+        ctor.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+        ctor.setTypeReference(TYPE_FUNCTION);
+        // NOTE: don't set a return type for constructors
+        ctor.setReturnTypeReference(null);
+
+        MethodInfo mInfo = iinfo.iInit;
+        int paramTypesSize = mInfo.getParamTypes().size();
+        final ParameterDefinition params[] = new ParameterDefinition[paramTypesSize + (mInfo.needsRest() ? 1 : 0)];
+        if (params.length > 0)
+        {
+            Vector<PooledValue> defaultValues = mInfo.getDefaultValues();
+            int firstOptionalParam = paramTypesSize - defaultValues.size();
+            for (int i = 0; i < paramTypesSize; i++)
+            {
+                final Name paramType = mInfo.getParamTypes().get(i);
+                final String paramName = i < mInfo.getParamNames().size() ? mInfo.getParamNames().get(i) : MethodInfo.UNKNOWN_PARAM_NAME;
+                params[i] = new ParameterDefinition(paramName);
+                params[i].setTypeReference(paramType == null ? TYPE_ANY : getReference(paramType));
+                if (i >= firstOptionalParam)
+                {
+                    Object defaultValue = defaultValues.get(i - firstOptionalParam).getValue();
+                    params[i].setDefaultValue(defaultValue);
+                }
+            }
+
+            if (mInfo.needsRest())
+            {
+                ParameterDefinition rest = new ParameterDefinition(MethodInfo.UNKNOWN_PARAM_NAME);
+                rest.setRest();
+                rest.setTypeReference(ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.ARRAY));
+                params[paramTypesSize] = rest;
+            }
+        }
+
+        ctor.setParameters(params);
+        ctor.setAsConstructor(classDefinition);
+        ctor.setImplicit();
+    }
+
+    private void setupCastFunction(InstanceInfo iinfo, InterfaceDefinition interfaceDefinition)
+    {
+        String castName = ScopedDefinitionTraitsVisitor.getDefinitionName(iinfo.name);
+
+        FunctionDefinition castFunc = new FunctionDefinition(castName);
+        castFunc.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+        castFunc.setReturnTypeReference(ReferenceFactory.resolvedReference(interfaceDefinition));
+        castFunc.setCastFunction();
+        castFunc.setImplicit();
+    }
+}


Mime
View raw message