[Petter Reinholdtsen]
> I asked on #gnash about the current status and what need to be fixed
> before a new release can be made, and was told by gg0 that there is
> one security issue and one blocking bug holding back the next release:
> 
> #40315 tummy_trouble.swf segfaults
>   <URL: http://sv.gnu.org/bugs/?40315 >
> 
> #39989 Assertion `(_shape1.subshapes().size() ==
>        _shape2.subshapes().size()) && (_shape2.subshapes().size() ==
>        1)' failed.
>   <URL: http://sv.gnu.org/bugs/?39989 >

I had a look at http://sv.gnu.org/bugs/?40315 and the comments there,
and the indication that the subshape changes was causing the problem.
The subshape changes also seem to be behind the problems in bug
#39989, and I decided to try to see if I could revert the subshape
changes and get the flash files working.

I managed to do this using the git history, and the patch to remove
the code is attached.  It might contain a bit more than it should, so
please review and see if parts of it is safe to apply.

Perhaps the changes in this patch should be applied to master and the
problematic changes moved to a branch until these bugs in the subshape
change are fixed?  It should be easier to fix now that two test cases
are available.  And perhaps some test suite tests could be created to
detect these problems automatically?

gg0 pointed me to <URL: http://wiki.gnashdev.org/Releasing > listing
the release procedure.  Time to release?

-- 
Happy hacking
Petter Reinholdtsen
diff --git a/libcore/Bitmap.cpp b/libcore/Bitmap.cpp
index cad8767..535b95b 100644
--- a/libcore/Bitmap.cpp
+++ b/libcore/Bitmap.cpp
@@ -91,7 +91,7 @@ Bitmap::construct(as_object* /*init*/)
 
     const size_t fillLeft = _shape.addFillStyle(fill);
 
-    Path bmpath(w, h, fillLeft, 0, 0);
+    Path bmpath(w, h, fillLeft, 0, 0, false);
     bmpath.drawLineTo(w, 0);
     bmpath.drawLineTo(0, 0);
     bmpath.drawLineTo(0, h);
diff --git a/libcore/DynamicShape.cpp b/libcore/DynamicShape.cpp
index 10bc3cb..4b5e1fc 100644
--- a/libcore/DynamicShape.cpp
+++ b/libcore/DynamicShape.cpp
@@ -41,7 +41,6 @@ DynamicShape::clear()
        _shape.clear();
        _currpath = 0; 
        _currfill = _currline = 0; 
-       _currsubshape.clear();
        // TODO: worth setting _changed=true ? 
 }
 
@@ -54,9 +53,8 @@ DynamicShape::display(Renderer& renderer, const Transform& 
xform) const
 void
 DynamicShape::add_path(const Path& pth)
 {
-       _currsubshape.addPath(pth);
-       _currpath = &_currsubshape.currentPath();
-       _changed = true;
+       _shape.addPath(pth);
+       _currpath = &_shape.currentPath();
 }
 
 void
@@ -82,11 +80,6 @@ DynamicShape::endFill()
                _y = _currpath->ap.y;
        }
 
-       if (_currline) {
-               _shape.addSubshape(_currsubshape);
-               _currsubshape.paths().clear(); // Retain style info
-       }
-
        // Remove reference to the "current" path, as
        // next drawing will happen on a different one
        _currpath = 0;
@@ -100,13 +93,12 @@ DynamicShape::beginFill(const FillStyle& f)
        // End previous fill
        endFill();
 
-
        _currfill = addFillStyle(f);
 
        // TODO: how to know wheter the fill should be set
        //       as *left* or *right* fill ?
        //       A quick test shows that *left* always work fine !
-       Path newPath(_x, _y, _currfill, 0, _currline);
+       Path newPath(_x, _y, _currfill, 0, _currline, true); 
        add_path(newPath);
 }
 
@@ -120,18 +112,12 @@ DynamicShape::startNewPath(bool newShape)
                _currpath->close();
        }
 
-       if (newShape) {
-               _shape.addSubshape(_currsubshape);
-               _currsubshape.paths().clear(); // Retain style info
-       }
-
-
        // The DrawingApiTest.swf file shows we should not
        // end the current fill when starting a new path.
 
        // A quick test shows that *left* always work fine !
        // More than that, using a *right* fill seems to break the tests !
-       Path newPath(_x, _y, _currfill, 0, _currline);
+       Path newPath(_x, _y, _currfill, 0, _currline, newShape);
        add_path(newPath);
 }
 
@@ -144,16 +130,11 @@ DynamicShape::finalize() const
        // Close any pending filled path (_currpath should be last path)
        if ( _currpath && _currfill)
        {
-               assert(!_currsubshape.paths().empty());
-               assert(_currpath == &(_currsubshape.paths().back()));
+               assert(!_shape.paths().empty());
+               assert(_currpath == &(_shape.paths().back()));
                _currpath->close();
        }
 
-       // This function being const seems to be at odds with its purpose...
-       _shape.addSubshape(_currsubshape);
-
-       _currsubshape.clear();
-
        // TODO: check consistency of fills and such !
 
        _changed = false;
@@ -195,7 +176,7 @@ DynamicShape::moveTo(boost::int32_t x, boost::int32_t y)
 void
 DynamicShape::lineTo(boost::int32_t x, boost::int32_t y, int swfVersion)
 {
-       if (!_currpath) startNewPath(false);
+       if (!_currpath) startNewPath(true); 
        assert(_currpath);
 
        _currpath->drawLineTo(x, y);
@@ -204,7 +185,7 @@ DynamicShape::lineTo(boost::int32_t x, boost::int32_t y, 
int swfVersion)
     SWFRect bounds = _shape.getBounds();
 
        unsigned thickness = _currline ? 
-        _currsubshape.lineStyles().back().getThickness() : 0;
+        _shape.lineStyles().back().getThickness() : 0;
 
        if (_currpath->size() == 1) {
                _currpath->expandBounds(bounds, thickness, swfVersion);
@@ -227,7 +208,7 @@ void
 DynamicShape::curveTo(boost::int32_t cx, boost::int32_t cy, 
                       boost::int32_t ax, boost::int32_t ay, int swfVersion)
 {
-       if (!_currpath) startNewPath(false);
+       if (!_currpath) startNewPath(true); 
        assert(_currpath);
 
        _currpath->drawCurveTo(cx, cy, ax, ay);
@@ -235,7 +216,7 @@ DynamicShape::curveTo(boost::int32_t cx, boost::int32_t cy,
     SWFRect bounds = _shape.getBounds();
 
        unsigned thickness = _currline ? 
-        _currsubshape.lineStyles().back().getThickness() : 0;
+        _shape.lineStyles().back().getThickness() : 0;
 
        if (_currpath->size() == 1) {
                _currpath->expandBounds(bounds, thickness, swfVersion);
@@ -260,15 +241,15 @@ DynamicShape::curveTo(boost::int32_t cx, boost::int32_t 
cy,
 size_t
 DynamicShape::addFillStyle(const FillStyle& stl)
 {
-    _currsubshape.addFillStyle(stl);
-    return _currsubshape.fillStyles().size();
+    _shape.addFillStyle(stl);
+    return _shape.fillStyles().size();
 }
 
 size_t
 DynamicShape::add_line_style(const LineStyle& stl)
 {
-    _currsubshape.addLineStyle(stl);
-    return _currsubshape.lineStyles().size();
+    _shape.addLineStyle(stl);
+    return _shape.lineStyles().size();
 }
        
 }      // end namespace gnash
diff --git a/libcore/DynamicShape.h b/libcore/DynamicShape.h
index c082c23..54287d5 100644
--- a/libcore/DynamicShape.h
+++ b/libcore/DynamicShape.h
@@ -147,7 +147,8 @@ public:
             const SWFMatrix& wm) const
        {
                finalize();
-               return _shape.pointTest(x, y, wm);
+               return geometry::pointTest(_shape.paths(), _shape.lineStyles(), 
x, y,
+                wm);
        }
 
     const SWF::ShapeRecord& shapeRecord() const {
@@ -180,8 +181,6 @@ private:
        /// If newShape is true the new shape will start a new subshape.
        void startNewPath(bool newShape);
 
-
-
        Path* _currpath;
 
        size_t _currfill;
@@ -196,8 +195,6 @@ private:
 
        mutable bool _changed;
 
-       mutable SWF::Subshape _currsubshape;
-
     /// The actual SWF::ShapeRecord wrapped by this class.
     //
     /// Mutable for lazy finalization.
diff --git a/libcore/FreetypeGlyphsProvider.cpp 
b/libcore/FreetypeGlyphsProvider.cpp
index 273bd10..608019d 100644
--- a/libcore/FreetypeGlyphsProvider.cpp
+++ b/libcore/FreetypeGlyphsProvider.cpp
@@ -99,15 +99,14 @@ public:
     {
         /// A default fill style is solid white.
         FillStyle f = SolidFill(rgba());
-        _subshape.addFillStyle(f);
-        _subshape.addPath(Path(_x, _y, 1, 0, 0));
-        _currPath = &_subshape.currentPath();
+        _shape.addFillStyle(f);
+        _shape.addPath(Path(_x, _y, 1, 0, 0, true));
+        _currPath = &_shape.currentPath();
     }
 
     void finish() 
     {
         _currPath->close();
-        _shape.addSubshape(_subshape);
     }
 
     ~OutlineWalker() {}
@@ -159,8 +158,8 @@ private:
         _x = static_cast<boost::int32_t>(to->x * _scale);
         _y = - static_cast<boost::int32_t>(to->y * _scale);
         _currPath->close();
-        _subshape.addPath(Path(_x, _y, 1, 0, 0));
-        _currPath = &_subshape.currentPath();
+        _shape.addPath(Path(_x, _y, 1, 0, 0, false));
+        _currPath = &_shape.currentPath();
         return 0;
     }
 
@@ -228,7 +227,6 @@ private:
         _shape.setBounds(bounds);
     }
 
-    SWF::Subshape _subshape;
     SWF::ShapeRecord& _shape;
 
     const float _scale;
diff --git a/libcore/Geometry.cpp b/libcore/Geometry.cpp
index d8cb7e3..350d249 100644
--- a/libcore/Geometry.cpp
+++ b/libcore/Geometry.cpp
@@ -161,6 +161,17 @@ pointTest(const std::vector<Path>& paths,
         float next_pen_y = pth.ap.y;
         float pen_x, pen_y;
 
+        if (pth.m_new_shape)
+        {
+            if (( even_odd && (counter % 2) != 0) ||
+                 (!even_odd && (counter != 0)) )
+            {
+                // the point is inside the previous subshape, so exit now
+                return true;
+            }
+
+            counter=0;
+        }
         if (pth.empty()) continue;
 
         // If the path has a line style, check for strokes there
diff --git a/libcore/Geometry.h b/libcore/Geometry.h
index 5ec7ca6..5836303 100644
--- a/libcore/Geometry.h
+++ b/libcore/Geometry.h
@@ -185,13 +185,16 @@ public:
     /// All paths with a higher index in the list belong to the same 
     /// shape unless they have m_new_shape==true on their own.
     /// Sub-shapes affect the order in which outlines and shapes are rendered.
+    bool m_new_shape;
     
     /// Default constructor
     //
     /// @param newShape
     ///    True if this path starts a new subshape
     ///
-    Path()
+    Path(bool newShape = false)
+        : 
+        m_new_shape(newShape)
     {
         reset(0, 0, 0, 0, 0);
     }
@@ -202,7 +205,8 @@ public:
         m_fill1(from.m_fill1),
         m_line(from.m_line),
         ap(from.ap),
-        m_edges(from.m_edges)
+        m_edges(from.m_edges),
+        m_new_shape(from.m_new_shape)                
     {
     }
     
@@ -229,7 +233,10 @@ public:
     /// @param newShape
     ///    True if this path starts a new subshape
     Path(boost::int32_t ax, boost::int32_t ay, 
-            unsigned fill0, unsigned fill1, unsigned line)
+            unsigned fill0, unsigned fill1, unsigned line, 
+            bool newShape)
+        :
+        m_new_shape(newShape)
     {
         reset(ax, ay, fill0, fill1, line);
     }
@@ -455,6 +462,18 @@ public:
         {
             (*it).transform(mat);
         }
+    }        
+
+    /// Set this path as the start of a new (sub)shape
+    void setNewShape() 
+    { 
+            m_new_shape=true; 
+    }
+
+    /// Return true if this path starts a new (sub)shape
+    bool getNewShape() const 
+    { 
+        return m_new_shape; 
     }
 
     /// Return true if this path contains no edges
@@ -537,6 +556,13 @@ public:
     {
         return m_edges[n];
     }
+
+    /// Returns true if this path begins a new subshape. <-- VERIFYME
+    bool isNewShape() const
+    {
+        return m_new_shape;
+    }
+
 }; // end of class Path
 
 namespace geometry
diff --git a/libcore/MorphShape.cpp b/libcore/MorphShape.cpp
index f1f67ee..98f4914 100644
--- a/libcore/MorphShape.cpp
+++ b/libcore/MorphShape.cpp
@@ -55,7 +55,8 @@ MorphShape::pointInShape(boost::int32_t x, boost::int32_t y) 
const
     //       shape).
     if (!_shape.getBounds().point_test(lp.x, lp.y)) return false;
 
-    return _shape.pointTest(lp.x, lp.y, wm);
+    return geometry::pointTest(_shape.paths(), _shape.lineStyles(),
+            lp.x, lp.y, wm);
 }
 
 void  
diff --git a/libcore/swf/DefineMorphShapeTag.cpp 
b/libcore/swf/DefineMorphShapeTag.cpp
index 4be974a..1315b85 100644
--- a/libcore/swf/DefineMorphShapeTag.cpp
+++ b/libcore/swf/DefineMorphShapeTag.cpp
@@ -106,32 +106,26 @@ DefineMorphShapeTag::read(SWFStream& in, TagType tag, 
movie_definition& md,
     }
 
     in.ensureBytes(4);
-    // Spec: Indicates offset to the second Shape.
+    // Offset. What is this for?
     static_cast<void>(in.read_u32());
 
     // Next line will throw ParserException on malformed SWF
     const boost::uint16_t fillCount = in.read_variable_count();
     
-    SWF::Subshape subshape1;
-    SWF::Subshape subshape2;
-
     for (size_t i = 0; i < fillCount; ++i) {
         OptionalFillPair fp = readFills(in, tag, md, true);
-        subshape1.addFillStyle(fp.first);
-        subshape2.addFillStyle(*fp.second);
+        _shape1.addFillStyle(fp.first);
+        _shape2.addFillStyle(*fp.second);
     }
 
     const boost::uint16_t lineCount = in.read_variable_count();
     LineStyle ls1, ls2;
     for (size_t i = 0; i < lineCount; ++i) {
         ls1.read_morph(in, tag, md, r, &ls2);
-        subshape1.addLineStyle(ls1);
-        subshape2.addLineStyle(ls2);
+        _shape1.addLineStyle(ls1);
+        _shape2.addLineStyle(ls2);
     }
 
-    _shape1.addSubshape(subshape1);
-    _shape2.addSubshape(subshape2);
-
     _shape1.read(in, tag, md, r);
     in.align();
     _shape2.read(in, tag, md, r);
@@ -145,8 +139,9 @@ DefineMorphShapeTag::read(SWFStream& in, TagType tag, 
movie_definition& md,
     // Starting bounds are the same as shape1
     _bounds = bounds1;
 
-    assert((_shape1.subshapes().size() == _shape2.subshapes().size()) &&
-        (_shape2.subshapes().size() == 1));
+    assert(_shape1.fillStyles().size() == _shape2.fillStyles().size());
+    assert(_shape1.lineStyles().size() == _shape2.lineStyles().size());
+
 }
 
 } // namespace SWF
diff --git a/libcore/swf/DefineShapeTag.cpp b/libcore/swf/DefineShapeTag.cpp
index faa279a..49ab8b5 100644
--- a/libcore/swf/DefineShapeTag.cpp
+++ b/libcore/swf/DefineShapeTag.cpp
@@ -73,7 +73,7 @@ bool
 DefineShapeTag::pointTestLocal(boost::int32_t x, boost::int32_t y, 
      const SWFMatrix& wm) const
 {
-    return _shape.pointTest(x, y, wm);
+    return geometry::pointTest(_shape.paths(), _shape.lineStyles(), x, y, wm);
 }
 
 
diff --git a/libcore/swf/ShapeRecord.cpp b/libcore/swf/ShapeRecord.cpp
index 23d8b0a..5b74e85 100644
--- a/libcore/swf/ShapeRecord.cpp
+++ b/libcore/swf/ShapeRecord.cpp
@@ -40,6 +40,8 @@ namespace {
         SWF::TagType tag, movie_definition& md, const RunResources& /*r*/);
     void readLineStyles(ShapeRecord::LineStyles& styles, SWFStream& in,
         SWF::TagType tag, movie_definition& md, const RunResources& /*r*/);
+    void computeBounds(SWFRect& bounds, const ShapeRecord::Paths& paths,
+        const ShapeRecord::LineStyles& lineStyles, int swfVersion);
 }
 
 // Functors for path and style manipulation.
@@ -136,6 +138,7 @@ private:
 
 } // anonymous namespace
 
+
 ShapeRecord::ShapeRecord(SWFStream& in, SWF::TagType tag, movie_definition& m,
         const RunResources& r)
 {
@@ -150,73 +153,60 @@ ShapeRecord::~ShapeRecord()
 {
 }
 
+ShapeRecord::ShapeRecord(const ShapeRecord& other)
+    :
+    _fillStyles(other._fillStyles),
+    _lineStyles(other._lineStyles),
+    _paths(other._paths),
+    _bounds(other._bounds)
+{
+}
+    
+ShapeRecord&
+ShapeRecord::operator=(const ShapeRecord& other)
+{
+    _fillStyles = other._fillStyles;
+    _lineStyles = other._lineStyles;
+    _paths = other._paths;
+    _bounds = other._bounds;
+    return *this;
+}
+
 void
 ShapeRecord::clear()
 {
+    _fillStyles.clear();
+    _lineStyles.clear();
+    _paths.clear();
     _bounds.set_null();
-    _subshapes.clear();
 }
 
 void
-Subshape::addFillStyle(const FillStyle& fs)
+ShapeRecord::addFillStyle(const FillStyle& fs)
 {
     _fillStyles.push_back(fs);
 }
 
-
-/// Find the bounds of this subhape, and return them in a rectangle.
-SWFRect
-Subshape::computeBounds(int swfVersion) const
-{
-    SWFRect bounds;
-
-    for (unsigned int i = 0; i < _paths.size(); i++) {
-        const Path& p = _paths[i];
-
-        unsigned thickness = 0;
-        if ( p.m_line ) {
-            // For glyph shapes m_line is allowed to be 1
-            // while no defined line styles are allowed.
-            if (lineStyles().empty()) {
-                // This is either a Glyph, for which m_line==1 is valid
-                // or a bug in the parser, which we have no way to
-                // check at this time
-                assert(p.m_line == 1);
-            }
-            else
-            {
-                thickness = lineStyles()[p.m_line-1].getThickness();
-            }
-        }
-        p.expandBounds(bounds, thickness, swfVersion);
-    }
-
-    return bounds;
-}
-
 void
-ShapeRecord::setLerp(const ShapeRecord& aa, const ShapeRecord& bb,
+ShapeRecord::setLerp(const ShapeRecord& a, const ShapeRecord& b,
         const double ratio)
 {
-       assert(_subshapes.size() == 1);
 
     // Update current bounds.
-    _bounds.set_lerp(aa.getBounds(), bb.getBounds(), ratio);
-    const Subshape& a = aa.subshapes().front();
-    const Subshape& b = bb.subshapes().front();
+    _bounds.set_lerp(a.getBounds(), b.getBounds(), ratio);
 
     // fill styles
     const FillStyles::const_iterator fs1 = a.fillStyles().begin();
     const FillStyles::const_iterator fs2 = b.fillStyles().begin();
 
-    std::for_each(_subshapes.front().fillStyles().begin(), 
_subshapes.front().fillStyles().end(),
+    std::for_each(_fillStyles.begin(), _fillStyles.end(),
             Lerp<FillStyles>(fs1, fs2, ratio));
 
     // line styles
     const LineStyles::const_iterator ls1 = a.lineStyles().begin();
     const LineStyles::const_iterator ls2 = b.lineStyles().begin();
 
-    std::for_each(_subshapes.front().lineStyles().begin(), 
_subshapes.front().lineStyles().end(),
+    std::for_each(_lineStyles.begin(), _lineStyles.end(),
             Lerp<LineStyles>(ls1, ls2, ratio));
 
     // This is used for cases in which number
@@ -228,8 +218,8 @@ ShapeRecord::setLerp(const ShapeRecord& aa, const 
ShapeRecord& bb,
     // shape
     const Paths& paths1 = a.paths();
     const Paths& paths2 = b.paths();
-    for (size_t i = 0, k = 0, n = 0; i < _subshapes.front().paths().size(); 
i++) {
-        Path& p = _subshapes.front().paths()[i];
+    for (size_t i = 0, k = 0, n = 0; i < _paths.size(); i++) {
+        Path& p = _paths[i];
         const Path& p1 = i < paths1.size() ? paths1[i] : empty_path;
         const Path& p2 = n < paths2.size() ? paths2[n] : empty_path;
 
@@ -261,28 +251,7 @@ ShapeRecord::setLerp(const ShapeRecord& aa, const 
ShapeRecord& bb,
             }
         }
     }
-}
-
-unsigned
-ShapeRecord::readStyleChange(SWFStream& in, size_t num_style_bits, size_t 
numStyles)
-{
-    if (!num_style_bits) {
-       return 0;
-    }
 
-    in.ensureBits(num_style_bits);
-    unsigned style = in.read_uint(num_style_bits);
-
-    if ( style > numStyles ) {
-        IF_VERBOSE_MALFORMED_SWF(
-            log_swferror(_("Invalid fill style %1% in "
-                           "style change record - %2% defined. "
-                           "Set to 0."), style, numStyles);
-        );
-        style = 0;
-    }
-
-    return style;
 }
 
 void
@@ -297,14 +266,6 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
                             tag == SWF::DEFINESHAPE4 ||
                             tag == SWF::DEFINESHAPE4_);
 
-    Subshape subshape;
-    if (!_subshapes.empty()) {
-       // This is a little naughty. In case we're reading DEFINEMORPH, we'll
-       // have been provided with styles, which are now copied....
-       subshape = _subshapes.front();
-       _subshapes.clear();
-    }
-
     if (styleInfo) {
         _bounds = readRect(in);
     
@@ -322,8 +283,8 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
             LOG_ONCE(log_unimpl("DEFINESHAPE4 edge boundaries and scales"));
         }
     
-        readFillStyles(subshape.fillStyles(), in, tag, m, r);
-        readLineStyles(subshape.lineStyles(), in, tag, m, r);
+        readFillStyles(_fillStyles, in, tag, m, r);
+        readLineStyles(_lineStyles, in, tag, m, r);
     }
 
     if (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2 ) {
@@ -371,6 +332,8 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
     // At the moment we just store each edge with
     // the full necessary info to render it, which
     // is simple but not optimally efficient.
+    int fill_base = 0;
+    int line_base = 0;
     int   x = 0, y = 0;
     Path  current_path;
 
@@ -387,17 +350,15 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
             if (flags == SHAPE_END) {  
                 // Store the current path if any.
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.m_edges.resize(0);
-                    _subshapes.push_back(subshape);
-                    subshape.clear();
                 }
                 break;
             }
             if (flags & SHAPE_MOVE) {  
                 // Store the current path if any, and prepare a fresh one.
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.m_edges.resize(0);
                 }
                 in.ensureBits(5);
@@ -422,15 +383,38 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
             if ((flags & SHAPE_FILLSTYLE0_CHANGE) && num_fill_bits > 0) {
                 // FillStyle_0_change = 1;
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.m_edges.resize(0);
                     current_path.ap.x = x;
                     current_path.ap.y = y;
                 }
-
-                unsigned style = readStyleChange(in, num_fill_bits,
-                    (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) ? 1 : 
subshape.fillStyles().size());
-
+                in.ensureBits(num_fill_bits);
+                unsigned style = in.read_uint(num_fill_bits);
+                if (style > 0) {
+                    style += fill_base;
+                }
+    
+                if (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) {
+                    if ( style > 1 ) {         // 0:hide 1:renderer
+                        IF_VERBOSE_MALFORMED_SWF(
+                             log_swferror(_("Invalid fill style %d in "
+                                     "fillStyle0Change record for font tag "
+                                     "(0 or 1 valid). Set to 0."), style);
+                        );
+                        style = 0;
+                    }
+                } else {
+                    // 1-based index
+                    if ( style > _fillStyles.size() ) {
+                        IF_VERBOSE_MALFORMED_SWF(
+                             log_swferror(_("Invalid fill style %d in "
+                                     "fillStyle0Change record - %d defined. "
+                                     "Set to 0."), style, _fillStyles.size());
+                        );
+                        style = 0;
+                    }
+                }
+    
                 current_path.setLeftFill(style);
 #if SHAPE_LOG
                 IF_VERBOSE_PARSE(
@@ -442,14 +426,37 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
             if ((flags & SHAPE_FILLSTYLE1_CHANGE) && num_fill_bits > 0) {
                 // FillStyle_1_change = 1;
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.m_edges.resize(0);
                     current_path.ap.x = x;
                     current_path.ap.y = y;
                 }
-                unsigned style = readStyleChange(in, num_fill_bits,
-                    (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) ? 1 : 
subshape.fillStyles().size());
-
+                in.ensureBits(num_fill_bits);
+                unsigned style = in.read_uint(num_fill_bits);
+                if (style > 0) {
+                    style += fill_base;
+                }
+    
+                if (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) {
+                    if ( style > 1 ) {          // 0:hide 1:renderer
+                        IF_VERBOSE_MALFORMED_SWF(
+                             log_swferror(_("Invalid fill style %d in "
+                                     "fillStyle1Change record for font tag "
+                                     "(0 or 1 valid). Set to 0."), style);
+                        );
+                        style = 0;
+                    }
+                } else {
+                    // 1-based index
+                    if ( style > _fillStyles.size() ) {
+                        IF_VERBOSE_MALFORMED_SWF(
+                            log_swferror(_("Invalid fill style %d in "
+                                    "fillStyle1Change record - %d defined. "
+                                    "Set to 0."), style, _fillStyles.size());
+                        );
+                        style = 0;
+                    }
+                }
                 current_path.setRightFill(style);
 #if SHAPE_LOG
                 IF_VERBOSE_PARSE (
@@ -461,14 +468,36 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
             if ((flags & SHAPE_LINESTYLE_CHANGE) && num_line_bits > 0) {
                 // line_style_change = 1;
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.m_edges.resize(0);
                     current_path.ap.x = x;
                     current_path.ap.y = y;
                 }
-                unsigned style = readStyleChange(in, num_line_bits,
-                    (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) ? 1 : 
subshape.lineStyles().size());
-
+                in.ensureBits(num_line_bits);
+                unsigned style = in.read_uint(num_line_bits);
+                if (style > 0) {
+                    style += line_base;
+                }
+                if (tag == SWF::DEFINEFONT || tag == SWF::DEFINEFONT2) {
+                    if ( style > 1 ) {         // 0:hide 1:renderer
+                        IF_VERBOSE_MALFORMED_SWF(
+                            log_swferror(_("Invalid line style %d in "
+                                    "lineStyleChange record for font tag "
+                                    "(0 or 1 valid). Set to 0."), style);
+                        );
+                        style = 0;
+                    }
+                } else {
+                    // 1-based index
+                    if (style > _lineStyles.size()) {
+                        IF_VERBOSE_MALFORMED_SWF(
+                            log_swferror(_("Invalid fill style %d in "
+                                    "lineStyleChange record - %d defined. "
+                                    "Set to 0."), style, _lineStyles.size());
+                        );
+                        style = 0;
+                    }
+                }
                 current_path.setLineStyle(style);
 #if SHAPE_LOG
                 IF_VERBOSE_PARSE(
@@ -491,15 +520,20 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
     
                 // Store the current path if any.
                 if (! current_path.empty()) {
-                    subshape.paths().push_back(current_path);
+                    _paths.push_back(current_path);
                     current_path.clear();
                 }
     
-                _subshapes.push_back(subshape);
-                subshape.clear();
+                // Tack on an empty path signalling a new shape.
+                // @@ need better understanding of whether this is 
correct??!?!!
+                // @@ i.e., we should just start a whole new shape here, right?
+                _paths.push_back(Path());
+                _paths.back().m_new_shape = true;
     
-                readFillStyles(subshape.fillStyles(), in, tag, m, r);
-                readLineStyles(subshape.lineStyles(), in, tag, m, r);
+                fill_base = _fillStyles.size();
+                line_base = _lineStyles.size();
+                readFillStyles(_fillStyles, in, tag, m, r);
+                readLineStyles(_lineStyles, in, tag, m, r);
     
                 in.ensureBits(8);
                 num_fill_bits = in.read_uint(4);
@@ -508,11 +542,10 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
         } else {
             // EDGERECORD
             in.ensureBits(1);
-            bool straight_edge = in.read_bit();
-            int num_bits = 2 + in.read_uint(4);
-            if (!straight_edge) {
+            bool edge_flag = in.read_bit();
+            if (edge_flag == 0) {
                 in.ensureBits(4);
-
+                int num_bits = 2 + in.read_uint(4);
                 // curved edge
                 in.ensureBits(4 * num_bits);
                 int cx = x + in.read_sint(num_bits);
@@ -526,13 +559,14 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
                             "%d %d - %d %d - %d %d"), x, y, cx, cy, ax, ay);
                 );
 #endif
-                current_path.drawCurveTo(cx, cy, ax, ay);
+                current_path.m_edges.push_back(Edge(cx, cy, ax, ay));
                 x = ax;
                 y = ay;
             } else {
                 // straight edge
                 in.ensureBits(5);
-                bool line_flag = in.read_bit();
+                int num_bits = 2 + in.read_uint(4);
+                bool  line_flag = in.read_bit();
                 int dx = 0, dy = 0;
                 if (line_flag)
                 {
@@ -543,7 +577,7 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
                 } else {
                     in.ensureBits(1);
                     bool vert_flag = in.read_bit();
-                    if (!vert_flag) {
+                    if (vert_flag == 0) {
                         // Horizontal line.
                         in.ensureBits(num_bits);
                         dx = in.read_sint(num_bits);
@@ -560,8 +594,8 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
                              "%d %d - %d %d"), x, y, x + dx, y + dy);
                 );
 #endif
-                current_path.drawLineTo(x + dx, y + dy);
-
+                current_path.m_edges.push_back(Edge(x + dx, y + dy,
+                            x + dx, y + dy));
                 x += dx;
                 y += dy;
             }
@@ -571,12 +605,7 @@ ShapeRecord::read(SWFStream& in, SWF::TagType tag, 
movie_definition& m,
     if (!styleInfo) {
         // TODO: performance would be improved by computing
         //       the bounds as edges are parsed.
-       _bounds.set_null();
-       for (Subshapes::const_iterator it = _subshapes.begin(),
-                       end = _subshapes.end(); it != end; ++it) {
-            SWFRect bounds = it->computeBounds(m.get_version());
-            _bounds.expand_to_rect(bounds);
-       }
+        computeBounds(_bounds, _paths, _lineStyles, m.get_version());
     }
 
 #ifdef GNASH_DEBUG_SHAPE_BOUNDS
@@ -651,6 +680,34 @@ readLineStyles(ShapeRecord::LineStyles& styles, SWFStream& 
in,
     }
 }
 
+// Find the bounds of this shape, and store them in the given rectangle.
+void
+computeBounds(SWFRect& bounds, const ShapeRecord::Paths& paths,
+        const ShapeRecord::LineStyles& lineStyles, int swfVersion)
+{
+    bounds.set_null();
+
+    for (unsigned int i = 0; i < paths.size(); i++) {
+        const Path& p = paths[i];
+
+        unsigned thickness = 0;
+        if ( p.m_line ) {
+            // For glyph shapes m_line is allowed to be 1
+            // while no defined line styles are allowed.
+            if (lineStyles.empty()) {
+                // This is either a Glyph, for which m_line==1 is valid
+                // or a bug in the parser, which we have no way to
+                // check at this time
+                assert(p.m_line == 1);
+            }
+            else
+            {
+                thickness = lineStyles[p.m_line-1].getThickness();
+            }
+        }
+        p.expandBounds(bounds, thickness, swfVersion);
+    }
+}
 
 
 } // anonymous namespace
@@ -660,14 +717,9 @@ operator<<(std::ostream& o, const ShapeRecord& sh)
 {
     o << boost::format("Shape Record: bounds %1%") % sh.getBounds();
 
-
-    for (ShapeRecord::Subshapes::const_iterator it = sh.subshapes().begin(),
-         end = sh.subshapes().end(); it != end; ++it) {
-
-        const ShapeRecord::FillStyles& fills = it->fillStyles();
-        std::copy(fills.begin(), fills.end(),
-                std::ostream_iterator<FillStyle>(o, ","));
-       }
+    const ShapeRecord::FillStyles& fills = sh.fillStyles();
+    std::copy(fills.begin(), fills.end(),
+            std::ostream_iterator<FillStyle>(o, ","));
 
     return o;
 }
diff --git a/libcore/swf/ShapeRecord.h b/libcore/swf/ShapeRecord.h
index 2f73612..b43cb58 100644
--- a/libcore/swf/ShapeRecord.h
+++ b/libcore/swf/ShapeRecord.h
@@ -22,7 +22,6 @@
 
 #include "Geometry.h"
 #include "LineStyle.h"
-#include "FillStyle.h"
 #include "SWFRect.h"
 
 #include <vector>
@@ -31,78 +30,12 @@
 namespace gnash {
     class movie_definition;
     class RunResources;
+    class FillStyle;
 }
 
 namespace gnash {
 namespace SWF {
 
-
-
-class Subshape {
-
-public:
-    typedef std::vector<FillStyle> FillStyles;
-    typedef std::vector<LineStyle> LineStyles;
-    typedef std::vector<Path> Paths;
-
-    const FillStyles& fillStyles() const {
-        return _fillStyles;
-    }
-
-    FillStyles& fillStyles() {
-        return _fillStyles;
-    }
-
-    const LineStyles& lineStyles() const {
-        return _lineStyles;
-    }
-
-    LineStyles& lineStyles() {
-        return _lineStyles;
-    }
-
-    const Paths& paths() const {
-        return _paths;
-    }
-
-    Paths& paths() {
-        return _paths;
-    }
-
-    /// For DynamicShape
-    //
-    /// TODO: rewrite DynamicShape to push paths when they're
-    /// finished and drop this.
-    Path& currentPath() {
-        return _paths.back();
-    }
-
-    void addFillStyle(const FillStyle& fs);
-
-    void addPath(const Path& path) {
-        _paths.push_back(path);
-    }
-
-    void addLineStyle(const LineStyle& ls) {
-        _lineStyles.push_back(ls);
-    }
-
-    void clear() {
-       _fillStyles.clear();
-       _lineStyles.clear();
-       _paths.clear();
-    }
-
-    SWFRect computeBounds(int swfVersion) const;
-
-private:
-    FillStyles _fillStyles;
-    LineStyles _lineStyles;
-    Paths _paths;
-};
-
-
-
 /// Holds information needed to draw a shape.
 //
 /// This does not correspond exactly to parsed record in a SWF file, but
@@ -116,20 +49,13 @@ private:
 //
 /// ShapeRecord objects are not ref-counted, so they may be stack-allocated
 /// or used in smart pointers.
-//
-/// A shape can have sub-shapes. This can happen when there are multiple
-/// layers of the same frame count. Flash combines them to one single shape.
-/// The problem with sub-shapes is, that outlines can be hidden by other
-/// layers so they must be rendered separately. In order to be sure outlines
-/// are show correctly, draw the subshapes contained in the ShapeRecord in
-/// sequence.
 class ShapeRecord
 {
 public:
-    typedef Subshape::FillStyles FillStyles;
-    typedef Subshape::LineStyles LineStyles;
-    typedef Subshape::Paths Paths;
-    typedef std::vector<Subshape> Subshapes;
+
+    typedef std::vector<FillStyle> FillStyles;
+    typedef std::vector<LineStyle> LineStyles;
+    typedef std::vector<Path> Paths;
 
     /// Construct a ShapeRecord.
     //
@@ -145,6 +71,11 @@ public:
     ShapeRecord(SWFStream& in, SWF::TagType tag, movie_definition& m,
             const RunResources& r);
 
+    /// Copy constructor
+    ShapeRecord(const ShapeRecord& other);
+    
+    /// Assignment operator
+    ShapeRecord& operator=(const ShapeRecord& other);
 
     ~ShapeRecord();
 
@@ -155,18 +86,30 @@ public:
     void read(SWFStream& in, SWF::TagType tag, movie_definition& m,
             const RunResources& r);
 
-    const Subshapes& subshapes() const {
-       return _subshapes;
+    const FillStyles& fillStyles() const {
+        return _fillStyles;
+    }
+    
+    const LineStyles& lineStyles() const {
+        return _lineStyles;
     }
 
-    void addSubshape(const Subshape& subshape) {
-       _subshapes.push_back(subshape);
+    const Paths& paths() const {
+        return _paths;
     }
 
     const SWFRect& getBounds() const {
         return _bounds;
     }
 
+    /// For DynamicShape
+    //
+    /// TODO: rewrite DynamicShape to push paths when they're
+    /// finished and drop this.
+    Path& currentPath() {
+        return _paths.back();
+    }
+
     /// Set to the lerp of two ShapeRecords.
     //
     /// Used in shape morphing.
@@ -176,26 +119,22 @@ public:
     /// Reset all shape data.
     void clear();
 
-    void setBounds(const SWFRect& bounds) {
-        _bounds = bounds;
+    void addFillStyle(const FillStyle& fs);
+
+    void addPath(const Path& path) {
+        _paths.push_back(path);
     }
 
-    bool pointTest(boost::int32_t x, boost::int32_t y,
-                   const SWFMatrix& wm) const {
-        for (SWF::ShapeRecord::Subshapes::const_iterator it = 
_subshapes.begin(),
-             end = _subshapes.end(); it != end; ++it) {
+    void addLineStyle(const LineStyle& ls) {
+        _lineStyles.push_back(ls);
+    }
 
-            if (geometry::pointTest(it->paths(), it->lineStyles(), x, y, wm)) {
-                   return true;
-            }
-        }
-        return false;
+    void setBounds(const SWFRect& bounds) {
+        _bounds = bounds;
     }
 
 private:
 
-    unsigned readStyleChange(SWFStream& in, size_t num_fill_bits, size_t 
numStyles);
-
     /// Shape record flags for use in parsing.
     enum ShapeRecordFlags {
         SHAPE_END = 0x00,
@@ -205,9 +144,12 @@ private:
         SHAPE_LINESTYLE_CHANGE = 0x08,
         SHAPE_HAS_NEW_STYLES = 0x10
     };
-
+    
+    FillStyles _fillStyles;
+    LineStyles _lineStyles;
+    Paths _paths;
     SWFRect _bounds;
-    Subshapes _subshapes;
+
 };
 
 std::ostream& operator<<(std::ostream& o, const ShapeRecord& sh);
diff --git a/librender/agg/Renderer_agg.cpp b/librender/agg/Renderer_agg.cpp
index 12b4142..ab2f59a 100644
--- a/librender/agg/Renderer_agg.cpp
+++ b/librender/agg/Renderer_agg.cpp
@@ -1027,8 +1027,6 @@ public:
   void drawGlyph(const SWF::ShapeRecord& shape, const rgba& color,
           const SWFMatrix& mat) 
   {
-    if (shape.subshapes().empty()) return;
-    assert(shape.subshapes().size() == 1);
     
     // select relevant clipping bounds
     if (shape.getBounds().is_null()) {
@@ -1039,7 +1037,7 @@ public:
     if (_clipbounds_selected.empty()) return; 
       
     GnashPaths paths;
-    apply_matrix_to_path(shape.subshapes().front().paths(), paths, mat);
+    apply_matrix_to_path(shape.paths(), paths, mat);
 
     // If it's a mask, we don't need the rest.
     if (m_drawing_mask) {
@@ -1057,7 +1055,7 @@ public:
     StyleHandler sh;
     build_agg_styles(sh, v, mat, SWFCxForm());
     
-    draw_shape(paths, agg_paths, sh, false);
+    draw_shape(-1, paths, agg_paths, sh, false);
     
     // NOTE: Do not use even-odd filling rule for glyphs!
     
@@ -1125,22 +1123,18 @@ public:
         if (!bounds_in_clipping_area(cur_bounds.getRange()))
         {
             return; // no need to draw
-        }
-
-        for (SWF::ShapeRecord::Subshapes::const_iterator it = 
shape.subshapes().begin(),
-             end = shape.subshapes().end(); it != end; ++it ) {
-
-            const SWF::ShapeRecord::FillStyles& fillStyles = it->fillStyles();
-            const SWF::ShapeRecord::LineStyles& lineStyles = it->lineStyles();
-            const SWF::ShapeRecord::Paths& paths = it->paths();
-
-            // select ranges
-            select_clipbounds(shape.getBounds(), xform.matrix);
+        }        
+        
+        const SWF::ShapeRecord::FillStyles& fillStyles = shape.fillStyles();
+        const SWF::ShapeRecord::LineStyles& lineStyles = shape.lineStyles();
+        const SWF::ShapeRecord::Paths& paths = shape.paths();
+        
+        // select ranges
+        select_clipbounds(shape.getBounds(), xform.matrix);
 
-            // render the DisplayObject's subshape.
-            drawShape(fillStyles, lineStyles, paths, xform.matrix,
-                      xform.colorTransform);
-        }
+        // render the DisplayObject's shape.
+        drawShape(fillStyles, lineStyles, paths, xform.matrix,
+                xform.colorTransform);
     }
 
     void drawShape(const std::vector<FillStyle>& FillStyles,
@@ -1156,7 +1150,7 @@ public:
         if (!have_shape && !have_outline) {
             // Early return for invisible character.
             return; 
-        }
+        }        
 
         GnashPaths paths;
         apply_matrix_to_path(objpaths, paths, mat);
@@ -1196,14 +1190,19 @@ public:
         StyleHandler sh;
         if (have_shape) build_agg_styles(sh, FillStyles, mat, cx);
 
+        // We need to separate sub-shapes during rendering. 
+        const unsigned int subshape_count = count_sub_shapes(paths);
 
+        for (unsigned int subshape=0; subshape<subshape_count; ++subshape)
+        {
             if (have_shape) {
-                draw_shape(paths, agg_paths, sh, true);        
+                draw_shape(subshape, paths, agg_paths, sh, true);        
             }
             if (have_outline)            {
-                draw_outlines(paths, agg_paths_rounded,
+                draw_outlines(subshape, paths, agg_paths_rounded,
                         line_styles, cx, mat);
             }
+        }
 
         // Clear selected clipbounds to ease debugging 
         _clipbounds_selected.clear();
@@ -1230,6 +1229,26 @@ public:
                 boost::bind(&Path::transform, _1, mat));
     } 
 
+
+  /// A shape can have sub-shapes. This can happen when there are multiple
+  /// layers of the same frame count. Flash combines them to one single shape.
+  /// The problem with sub-shapes is, that outlines can be hidden by other
+  /// layers so they must be rendered separately. 
+  unsigned int count_sub_shapes(const GnashPaths &path_in)
+  {
+    unsigned int sscount=1;
+    const size_t pcnt = path_in.size();
+    
+    for (size_t pno=0; pno<pcnt; ++pno) {
+      const Path& this_path = path_in[pno];
+      
+      if (this_path.m_new_shape)
+        sscount++;
+    }
+    
+    return sscount;
+  }
+
   // Version of buildPaths that uses rounded coordinates (pixel hinting)
   // for line styles that want it.  
   // This is used for outlines which are aligned to the pixel grid to avoid
@@ -1417,7 +1436,7 @@ public:
   /// @param subshape_id
   ///    Defines which subshape to draw. -1 means all subshapes.
   ///
-  void draw_shape(const GnashPaths &paths,
+  void draw_shape(int subshape_id, const GnashPaths &paths,
     const AggPaths& agg_paths,  
     StyleHandler& sh, bool even_odd) {
     
@@ -1429,7 +1448,7 @@ public:
       
       scanline_type sl;
       
-      draw_shape_impl<scanline_type> (paths, agg_paths, 
+      draw_shape_impl<scanline_type> (subshape_id, paths, agg_paths, 
         sh, even_odd, sl);
         
     } else {
@@ -1440,7 +1459,7 @@ public:
       
       scanline_type sl(_alphaMasks.back().getMask());
       
-      draw_shape_impl<scanline_type> (paths, agg_paths, 
+      draw_shape_impl<scanline_type> (subshape_id, paths, agg_paths, 
         sh, even_odd, sl);
         
     }
@@ -1451,7 +1470,7 @@ public:
   /// one with and one without an alpha mask. This makes drawing without masks
   /// much faster.  
   template <class scanline_type>
-  void draw_shape_impl(const GnashPaths &paths,
+  void draw_shape_impl(int subshape_id, const GnashPaths &paths,
     const AggPaths& agg_paths,
     StyleHandler& sh, bool even_odd, scanline_type& sl) {
     /*
@@ -1493,6 +1512,8 @@ public:
       
       applyClipBox<ras_type> (rasc, *bounds);
       
+      int current_subshape=0;
+        
       // push paths to AGG
       const size_t pcount = paths.size();
   
@@ -1503,11 +1524,19 @@ public:
           const_cast<agg::path_storage&>(agg_paths[pno]);
         
         agg::conv_curve<agg::path_storage> curve(this_path_agg);        
-
+        
+        if (this_path_gnash.m_new_shape) ++current_subshape;
+          
+        if ((subshape_id >= 0) && (current_subshape!=subshape_id)) {
+          // Skip this path as it is not part of the requested sub-shape.
+          continue;
+        }
+        
         if ((this_path_gnash.m_fill0==0) && (this_path_gnash.m_fill1==0)) {
           // Skip this path as it contains no fill style
           continue;
         } 
+                
         
         // Tell the rasterizer which styles the following path will use.
         // The good thing is, that it already supports two fill styles out of
@@ -1519,7 +1548,7 @@ public:
         rasc.add_path(curve);
       
       }
-
+              
       agg::render_scanlines_compound_layered(rasc, sl, rbase, alloc, sh);
     }
     
@@ -1627,7 +1656,7 @@ public:
 
 
   /// Just like draw_shapes() except that it draws an outline.
-  void draw_outlines(const GnashPaths &paths,
+  void draw_outlines(int subshape_id, const GnashPaths &paths,
     const AggPaths& agg_paths,
     const std::vector<LineStyle> &line_styles, const SWFCxForm& cx,
     const SWFMatrix& linestyle_matrix) {
@@ -1640,7 +1669,7 @@ public:
       
       scanline_type sl;
       
-      draw_outlines_impl<scanline_type> (paths, agg_paths, 
+      draw_outlines_impl<scanline_type> (subshape_id, paths, agg_paths, 
         line_styles, cx, linestyle_matrix, sl);
         
     } else {
@@ -1651,7 +1680,7 @@ public:
       
       scanline_type sl(_alphaMasks.back().getMask());
       
-      draw_outlines_impl<scanline_type> (paths, agg_paths,
+      draw_outlines_impl<scanline_type> (subshape_id, paths, agg_paths,
         line_styles, cx, linestyle_matrix, sl);
         
     }
@@ -1661,7 +1690,7 @@ public:
 
   /// Template for draw_outlines(), see draw_shapes_impl().
   template <class scanline_type>
-  void draw_outlines_impl(const GnashPaths &paths,
+  void draw_outlines_impl(int subshape_id, const GnashPaths &paths,
     const AggPaths& agg_paths,
     const std::vector<LineStyle> &line_styles, const SWFCxForm& cx, 
     const SWFMatrix& linestyle_matrix, scanline_type& sl) {
@@ -1698,6 +1727,8 @@ public:
           
       applyClipBox<ras_type> (ras, *bounds);
       
+      int current_subshape=0;
+
       for (size_t pno=0, pcount=paths.size(); pno<pcount; ++pno) {
 
         const Path& this_path_gnash = paths[pno];
@@ -1705,6 +1736,14 @@ public:
         agg::path_storage &this_path_agg = 
           const_cast<agg::path_storage&>(agg_paths[pno]);
         
+        if (this_path_gnash.m_new_shape)
+          ++current_subshape;
+          
+        if ((subshape_id>=0) && (current_subshape!=subshape_id)) {
+          // Skip this path as it is not part of the requested sub-shape.
+          continue;
+        }
+        
         if (this_path_gnash.m_line==0) {
           // Skip this path as it contains no line style
           continue;
@@ -1713,7 +1752,7 @@ public:
         agg::conv_curve< agg::path_storage > curve(this_path_agg); // to 
render curves
         agg::conv_stroke< agg::conv_curve < agg::path_storage > > 
           stroke(curve);  // to get an outline
-
+        
         const LineStyle& lstyle = line_styles[this_path_gnash.m_line-1];
           
         int thickness = lstyle.getThickness();
diff --git a/librender/cairo/Renderer_cairo.cpp 
b/librender/cairo/Renderer_cairo.cpp
index c597dd4..99c1301 100644
--- a/librender/cairo/Renderer_cairo.cpp
+++ b/librender/cairo/Renderer_cairo.cpp
@@ -950,6 +950,31 @@ Renderer_cairo::draw_subshape(const PathVec& path_vec, 
const SWFMatrix& mat,
     draw_outlines(path_vec, line_styles, cx, mat);
 }
 
+
+std::vector<PathVec::const_iterator>
+Renderer_cairo::find_subshapes(const PathVec& path_vec)
+{
+    std::vector<PathVec::const_iterator> subshapes;
+    
+    PathVec::const_iterator it = path_vec.begin();
+    PathVec::const_iterator end = path_vec.end();
+    
+    subshapes.push_back(it);
+    ++it;
+
+    for (;it != end; ++it) {
+        const Path& cur_path = *it;
+  
+        if (cur_path.m_new_shape) {
+            subshapes.push_back(it); 
+        }  
+    } 
+  
+    subshapes.push_back(end);
+    
+    return subshapes;
+}
+
 void
 Renderer_cairo::draw_mask(const PathVec& path_vec)
 {    
@@ -986,23 +1011,40 @@ Renderer_cairo::apply_matrix_to_paths(std::vector<Path>& 
paths,
 void
 Renderer_cairo::drawShape(const SWF::ShapeRecord& shape, const Transform& 
xform)
 {
+    const PathVec& path_vec = shape.paths();
+    
+    if (!path_vec.size()) {
+        return;    
+    }
+    
     cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_EVEN_ODD); // TODO: Move to init
+        
+    if (_drawing_mask) {      
+        PathVec scaled_path_vec = path_vec;
+        
+        apply_matrix_to_paths(scaled_path_vec, xform.matrix);
+        draw_mask(scaled_path_vec); 
+        return;
+    }
     
     CairoScopeMatrix mat_transformer(_cr, xform.matrix);
 
-    for (SWF::ShapeRecord::Subshapes::const_iterator it = 
shape.subshapes().begin(),
-         end = shape.subshapes().end(); it != end; ++it) {
+    std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
+    
+    const std::vector<FillStyle>& FillStyles = shape.fillStyles();
+    const std::vector<LineStyle>& line_styles = shape.lineStyles();
 
-        if (_drawing_mask) {      
-            PathVec scaled_path_vec = it->paths();
+    for (size_t i = 0; i < subshapes.size()-1; ++i) {
+        PathVec subshape_paths;
         
-            apply_matrix_to_paths(scaled_path_vec, xform.matrix);
-            draw_mask(scaled_path_vec); 
-            continue;
+        if (subshapes[i] != subshapes[i+1]) {
+            subshape_paths = PathVec(subshapes[i], subshapes[i+1]);
+        } else {
+            subshape_paths.push_back(*subshapes[i]);
         }
-
-        draw_subshape(it->paths(), xform.matrix, xform.colorTransform,
-                it->fillStyles(), it->lineStyles());
+        
+        draw_subshape(subshape_paths, xform.matrix, xform.colorTransform,
+                FillStyles, line_styles);
     }
 }
   
@@ -1010,18 +1052,14 @@ void
 Renderer_cairo::drawGlyph(const SWF::ShapeRecord& rec, const rgba& color,
                           const SWFMatrix& mat)
 {
-    if (rec.subshapes().empty() || rec.getBounds().is_null()) {
-        return;
-    }
-
     SWFCxForm dummy_cx;
     std::vector<FillStyle> glyph_fs;
     
     FillStyle coloring = FillStyle(SolidFill(color));
     
     glyph_fs.push_back(coloring);
-
-    const PathVec& path_vec = rec.subshapes().front().paths();
+    
+    const PathVec& path_vec = rec.paths();
     
     std::vector<LineStyle> dummy_ls;
     
diff --git a/librender/opengl/Renderer_ogl.cpp 
b/librender/opengl/Renderer_ogl.cpp
index 1d4102e..a15057c 100644
--- a/librender/opengl/Renderer_ogl.cpp
+++ b/librender/opengl/Renderer_ogl.cpp
@@ -1256,7 +1256,7 @@ public:
     float prev_cx = cur_end.cp.x;
     float prev_cy = cur_end.cp.y;        
                 
-    Path newpath(cur_end.ap.x, cur_end.ap.y, cur_path.m_fill1, 
cur_path.m_fill0, cur_path.m_line);
+    Path newpath(cur_end.ap.x, cur_end.ap.y, cur_path.m_fill1, 
cur_path.m_fill0, cur_path.m_line, cur_path.m_new_shape);
     
     float prev_ax = cur_end.ap.x;
     float prev_ay = cur_end.ap.y; 
@@ -1629,6 +1629,32 @@ public:
   }
   
   
+  std::vector<PathVec::const_iterator>
+  find_subshapes(const PathVec& path_vec)
+  {
+    std::vector<PathVec::const_iterator> subshapes;
+    
+    PathVec::const_iterator it = path_vec.begin(),
+                            end = path_vec.end();
+    
+    subshapes.push_back(it);
+    ++it;
+
+    for (;it != end; ++it) {
+      const Path& cur_path = *it;
+    
+      if (cur_path.m_new_shape) {
+        subshapes.push_back(it); 
+      } 
+    }
+
+    if (subshapes.back() != end) {
+      subshapes.push_back(end);
+    }
+    
+    return subshapes;
+  }
+  
   /// Takes a path and translates it using the given SWFMatrix.
   void
   apply_matrix_to_paths(std::vector<Path>& paths, const SWFMatrix& mat)
@@ -1723,48 +1749,54 @@ public:
 
   virtual void drawShape(const SWF::ShapeRecord& shape, const Transform& xform)
   {
-    if (shape.subshapes().empty()) {
-        return;
-    }
-    
-    oglScopeMatrix scope_mat(xform.matrix);
-
-    for (SWF::ShapeRecord::Subshapes::const_iterator it = 
shape.subshapes().begin(),
-         end = shape.subshapes().end(); it != end; ++it) {
-        const PathVec& path_vec = it->paths();
+  
+    const PathVec& path_vec = shape.paths();
 
-        if (!path_vec.size()) {
-            // No paths. Nothing to draw...
-            return;
-        }
+    if (!path_vec.size()) {
+      // No paths. Nothing to draw...
+      return;
+    }
     
-        if (_drawing_mask) {
-            PathVec scaled_path_vec = path_vec;
+    if (_drawing_mask) {
+      PathVec scaled_path_vec = path_vec;
       
-            apply_matrix_to_paths(scaled_path_vec, xform.matrix);
-            draw_mask(scaled_path_vec); 
-            continue;
-        }    
+      apply_matrix_to_paths(scaled_path_vec, xform.matrix);
+      draw_mask(scaled_path_vec); 
+      return;
+    }    
+    
+    bool have_shape, have_outline;
     
-        bool have_shape, have_outline;
+    analyze_paths(path_vec, have_shape, have_outline);
     
-        analyze_paths(path_vec, have_shape, have_outline);
+    if (!have_shape && !have_outline) {
+      return; // invisible character
+    }    
     
-        if (!have_shape && !have_outline) {
-            continue; // invisible character
-        }  
+    oglScopeMatrix scope_mat(xform.matrix);
 
-        draw_subshape(it->paths(), xform.matrix, xform.colorTransform,
-                      it->fillStyles(), it->lineStyles());
+    std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
+    
+    const std::vector<FillStyle>& FillStyles = shape.fillStyles();
+    const std::vector<LineStyle>& line_styles = shape.lineStyles();
+    
+    for (size_t i = 0; i < subshapes.size()-1; ++i) {
+      PathVec subshape_paths;
+      
+      if (subshapes[i] != subshapes[i+1]) {
+        subshape_paths = PathVec(subshapes[i], subshapes[i+1]);
+      } else {
+        subshape_paths.push_back(*subshapes[i]);
+      }
+      
+      draw_subshape(subshape_paths, xform.matrix, xform.colorTransform,
+              FillStyles, line_styles);
     }
   }
 
   virtual void drawGlyph(const SWF::ShapeRecord& rec, const rgba& c,
          const SWFMatrix& mat)
   {
-    if (rec.subshapes().empty()) {
-        return;
-    }
     if (_drawing_mask) abort();
     SWFCxForm dummy_cx;
     std::vector<FillStyle> glyph_fs;
@@ -1777,7 +1809,7 @@ public:
     
     oglScopeMatrix scope_mat(mat);
     
-    draw_subshape(rec.subshapes().front().paths(), mat, dummy_cx, glyph_fs, 
dummy_ls);
+    draw_subshape(rec.paths(), mat, dummy_cx, glyph_fs, dummy_ls);
   }
 
   virtual void set_scale(float xscale, float yscale) {
_______________________________________________
Gnash-dev mailing list
Gnash-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnash-dev

Reply via email to