public SwfDisplayList Visit(PlaceObjectTag tag, SwfDisplayList dl)
        {
            var is_shape  = Library.HasDefine <SwfLibraryShapeDefine>(tag.CharacterId);
            var is_sprite = Library.HasDefine <SwfLibrarySpriteDefine>(tag.CharacterId);
            SwfDisplayInstance new_inst = null;

            if (is_shape)
            {
                new_inst = new SwfDisplayShapeInstance();
            }
            else if (is_sprite)
            {
                new_inst = new SwfDisplaySpriteInstance();
            }
            if (new_inst != null)
            {
                new_inst.Id             = tag.CharacterId;
                new_inst.Depth          = tag.Depth;
                new_inst.ClipDepth      = 0;
                new_inst.Visible        = true;
                new_inst.Matrix         = tag.Matrix;
                new_inst.BlendMode      = SwfBlendMode.identity;
                new_inst.FilterList     = SwfSurfaceFilters.identity;
                new_inst.ColorTransform = tag.ColorTransform;
                dl.Instances.Add(new_inst.Depth, new_inst);
            }
            return(dl);
        }
        public SwfDisplayList Visit(PlaceObject2Tag tag, SwfDisplayList dl)
        {
            var is_shape  = tag.HasCharacter && Library.HasDefine <SwfLibraryShapeDefine>(tag.CharacterId);
            var is_sprite = tag.HasCharacter && Library.HasDefine <SwfLibrarySpriteDefine>(tag.CharacterId);

            if (tag.HasCharacter)
            {
                SwfDisplayInstance old_inst = null;
                if (tag.Move)                     // replace character
                {
                    if (dl.Instances.TryGetValue(tag.Depth, out old_inst))
                    {
                        dl.Instances.Remove(tag.Depth);
                    }
                }
                // new character
                SwfDisplayInstance new_inst = null;
                if (is_shape)
                {
                    new_inst = new SwfDisplayShapeInstance();
                }
                else if (is_sprite)
                {
                    new_inst = new SwfDisplaySpriteInstance();
                }
                if (new_inst != null)
                {
                    new_inst.Id             = tag.CharacterId;
                    new_inst.Depth          = tag.Depth;
                    new_inst.ClipDepth      = tag.HasClipDepth      ? tag.ClipDepth      : (old_inst != null ? old_inst.ClipDepth      : (ushort)0);
                    new_inst.Visible        = true;
                    new_inst.Matrix         = tag.HasMatrix         ? tag.Matrix         : (old_inst != null ? old_inst.Matrix         : SwfMatrix.identity);
                    new_inst.BlendMode      = SwfBlendMode.identity;
                    new_inst.FilterList     = SwfSurfaceFilters.identity;
                    new_inst.ColorTransform = tag.HasColorTransform ? tag.ColorTransform : (old_inst != null ? old_inst.ColorTransform : SwfColorTransform.identity);
                    dl.Instances.Add(new_inst.Depth, new_inst);
                }
            }
            else if (tag.Move)                   // move character
            {
                SwfDisplayInstance inst;
                if (dl.Instances.TryGetValue(tag.Depth, out inst))
                {
                    if (tag.HasClipDepth)
                    {
                        inst.ClipDepth = tag.ClipDepth;
                    }
                    if (tag.HasMatrix)
                    {
                        inst.Matrix = tag.Matrix;
                    }
                    if (tag.HasColorTransform)
                    {
                        inst.ColorTransform = tag.ColorTransform;
                    }
                }
            }
            return(dl);
        }
        bool IsSpriteTimelineEnd(SwfDisplaySpriteInstance sprite)
        {
            var sprite_def = Library.FindDefine <SwfLibrarySpriteDefine>(sprite.Id);

            if (sprite_def != null && sprite.CurrentTag < sprite_def.ControlTags.Tags.Count)
            {
                return(false);
            }
            var children = sprite.DisplayList.Instances.Values
                           .Where(p => p.Type == SwfDisplayInstanceType.Sprite)
                           .Select(p => p as SwfDisplaySpriteInstance);

            foreach (var child in children)
            {
                if (!IsSpriteTimelineEnd(child))
                {
                    return(false);
                }
            }
            return(true);
        }