gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r12346: Rewrite fill style handling


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r12346: Rewrite fill style handling to make it easier to extend. Fix bug #26670
Date: Mon, 02 Aug 2010 09:54:02 +0200
User-agent: Bazaar (2.0.3)

------------------------------------------------------------
revno: 12346 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Mon 2010-08-02 09:54:02 +0200
message:
  Rewrite fill style handling to make it easier to extend. Fix bug #26670
  and improve SWF8 gradient fills, including implementing dynamic focal
  fills.
added:
  testsuite/misc-ming.all/GradientFillTest.as
renamed:
  libcore/fill_style.cpp => libcore/FillStyle.cpp
  libcore/fill_style.h => libcore/FillStyle.h
modified:
  libbase/GnashNumeric.h
  libcore/Bitmap.cpp
  libcore/DisplayObject.cpp
  libcore/DisplayObject.h
  libcore/DynamicShape.cpp
  libcore/DynamicShape.h
  libcore/FreetypeGlyphsProvider.cpp
  libcore/Geometry.h
  libcore/LineStyle.cpp
  libcore/LineStyle.h
  libcore/Makefile.am
  libcore/MovieClip.h
  libcore/RGBA.cpp
  libcore/RGBA.h
  libcore/SWFMatrix.cpp
  libcore/SWFMatrix.h
  libcore/SWFRect.cpp
  libcore/asobj/MovieClip_as.cpp
  libcore/swf/DefineButtonTag.cpp
  libcore/swf/DefineEditTextTag.cpp
  libcore/swf/DefineMorphShapeTag.cpp
  libcore/swf/DefineTextTag.cpp
  libcore/swf/PlaceObject2Tag.cpp
  libcore/swf/PlaceObject2Tag.h
  libcore/swf/SWF.h
  libcore/swf/SetBackgroundColorTag.h
  libcore/swf/ShapeRecord.cpp
  libcore/swf/ShapeRecord.h
  libcore/swf/TextRecord.cpp
  librender/Renderer.h
  librender/Renderer_agg.cpp
  librender/Renderer_agg_style.h
  librender/Renderer_cairo.cpp
  librender/Renderer_cairo.h
  librender/Renderer_ogl.cpp
  testsuite/libcore.all/ClassSizes.cpp
  testsuite/libcore.all/MatrixTest.cpp
  testsuite/misc-ming.all/DrawingApiTest.as
  testsuite/misc-ming.all/DrawingApiTestRunner.cpp
  testsuite/misc-ming.all/Makefile.am
  libcore/FillStyle.cpp
  libcore/FillStyle.h
=== modified file 'libbase/GnashNumeric.h'
--- a/libbase/GnashNumeric.h    2010-01-11 06:41:38 +0000
+++ b/libbase/GnashNumeric.h    2010-07-31 16:10:47 +0000
@@ -68,8 +68,9 @@
        return std::max<T>(min, std::min<T>(i, max));
 }
 
-inline float
-flerp(float a, float b, float f)
+template<typename T>
+inline T
+lerp(T a, T b, T f)
 {
     return (b - a) * f + a;
 }

=== modified file 'libcore/Bitmap.cpp'
--- a/libcore/Bitmap.cpp        2010-07-19 08:08:00 +0000
+++ b/libcore/Bitmap.cpp        2010-07-31 14:22:03 +0000
@@ -19,7 +19,7 @@
 #include "Bitmap.h"
 #include "flash/display/BitmapData_as.h"
 #include "GnashImage.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "DynamicShape.h"
 #include "SWFRect.h"
 #include "Renderer.h"
@@ -168,8 +168,10 @@
 
     SWFMatrix mat;
     mat.set_scale(1.0 / 20, 1.0 / 20);
-    fill_style fill(bitmap(), mat);
-    const size_t fillLeft = _shape.add_fill_style(fill);
+
+    // Can this be tiled?
+    FillStyle fill(BitmapFill(BitmapFill::CLIPPED, bitmap(), mat));
+    const size_t fillLeft = _shape.addFillStyle(fill);
 
     Path bmpath(w, h, fillLeft, 0, 0, false);
     bmpath.drawLineTo(w, 0);

=== modified file 'libcore/DisplayObject.cpp'
--- a/libcore/DisplayObject.cpp 2010-07-11 08:00:59 +0000
+++ b/libcore/DisplayObject.cpp 2010-07-31 16:16:12 +0000
@@ -91,7 +91,7 @@
     _rotation(0),
     _depth(0),
     _volume(100),
-    m_ratio(0),
+    _ratio(0),
     m_clip_depth(noClipDepthValue),
     _mask(0),
     _maskee(0),

=== modified file 'libcore/DisplayObject.h'
--- a/libcore/DisplayObject.h   2010-07-10 13:40:04 +0000
+++ b/libcore/DisplayObject.h   2010-07-31 16:16:12 +0000
@@ -339,12 +339,12 @@
         }
     }
 
-    int get_ratio() const { return m_ratio; }
+    int get_ratio() const { return _ratio; }
 
     void set_ratio(int r)
     {
-        if (r != m_ratio) set_invalidated(__FILE__, __LINE__); 
-        m_ratio = r;       
+        if (r != _ratio) set_invalidated(__FILE__, __LINE__); 
+        _ratio = r;       
     }
 
     /// Returns the clipping depth (if any) of this DisplayObject.
@@ -1050,7 +1050,7 @@
     ///
     int _volume;
 
-    int m_ratio;
+    int _ratio;
     int m_clip_depth;
 
     /// The DisplayObject masking this instance (if any)

=== modified file 'libcore/DynamicShape.cpp'
--- a/libcore/DynamicShape.cpp  2010-03-13 18:00:33 +0000
+++ b/libcore/DynamicShape.cpp  2010-07-31 14:05:26 +0000
@@ -17,7 +17,7 @@
 
 #include "smart_ptr.h"
 #include "DynamicShape.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "Renderer.h"
 #include "DisplayObject.h"
 
@@ -88,49 +88,12 @@
 }
 
 void
-DynamicShape::beginFill(const rgba& color)
-{
-       // End previous fill
-       endFill();
-
-       // Add the new fill style and set as current
-       fill_style style; style.setSolid(color);
-       _currfill = add_fill_style(style);
-
-       // 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, true); 
-       add_path(newPath);
-}
-
-void
-DynamicShape::beginLinearGradientFill(const std::vector<gradient_record>& 
grad, const SWFMatrix& mat)
-{
-       // Add the new fill style and set as current
-       fill_style style;
-    style.setLinearGradient(grad, mat);
-
-       endFill();
-
-       _currfill = add_fill_style(style);
-       // 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, true);
-       add_path(newPath);
-}
-
-void
-DynamicShape::beginRadialGradientFill(const std::vector<gradient_record>& 
grad, const SWFMatrix& mat)
-{
-
-       // End previous fill
-       endFill();
-
-       // Add the new fill style and set as current
-       fill_style style; style.setRadialGradient(grad, mat);
-       _currfill = add_fill_style(style);
+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 ?
@@ -276,7 +239,7 @@
 }
 
 size_t
-DynamicShape::add_fill_style(const fill_style& stl)
+DynamicShape::addFillStyle(const FillStyle& stl)
 {
     _shape.addFillStyle(stl);
     return _shape.fillStyles().size();

=== modified file 'libcore/DynamicShape.h'
--- a/libcore/DynamicShape.h    2010-07-28 07:57:23 +0000
+++ b/libcore/DynamicShape.h    2010-07-31 14:05:26 +0000
@@ -27,8 +27,8 @@
 namespace gnash {
     class DisplayObject;
     class Renderer;
-    class fill_style;
-    class gradient_record;
+    class FillStyle;
+    class GradientRecord;
 }
 
 namespace gnash {
@@ -64,15 +64,7 @@
                  boost::int32_t ax, boost::int32_t ay, int swfVersion);
 
        /// Start drawing with a solid fill
-       void beginFill(const rgba& color);
-
-       /// Start drawing with a linear gradient fill
-       void beginLinearGradientFill(const std::vector<gradient_record>& grad,
-            const SWFMatrix& mat);
-
-       /// Start drawing with a radial gradient fill
-       void beginRadialGradientFill(const std::vector<gradient_record>& grad,
-            const SWFMatrix& mat);
+       void beginFill(const FillStyle& f);
 
        /// Close an existing filled path, if any.
        void endFill();
@@ -129,7 +121,7 @@
        ///     This offset is the one required to properly
        ///     reference it in gnash::path instances.
        ///
-       size_t add_fill_style(const fill_style& stl);
+       size_t addFillStyle(const FillStyle& stl);
 
        /// \brief
        /// Add a line style, possibly reusing an existing

=== renamed file 'libcore/fill_style.cpp' => 'libcore/FillStyle.cpp'
--- a/libcore/fill_style.cpp    2010-07-12 21:18:16 +0000
+++ b/libcore/FillStyle.cpp     2010-08-01 07:47:27 +0000
@@ -1,4 +1,4 @@
-// fill_style.cpp:  Graphical region filling styles, for Gnash.
+// FillStyle.cpp:  Graphical region filling styles, for Gnash.
 // 
 //   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // 
@@ -17,10 +17,13 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-// Based on work of Thatcher Ulrich <address@hidden> 2003
+#include "FillStyle.h"
+
+#include <iostream> 
+#include <boost/variant.hpp>
+#include <boost/optional.hpp>
 
 #include "smart_ptr.h"
-#include "fill_style.h"
 #include "log.h"
 #include "SWFStream.h"
 #include "movie_definition.h"
@@ -31,632 +34,422 @@
 #include "RunResources.h"
 #include "GnashImage.h"
 
-#include <cmath> // sqrt, floor
-#include <iostream> // for output operator
 
 namespace gnash {
 
+// Forward declarations
+namespace {
+    rgba sampleGradient(const GradientFill& fill, boost::uint8_t ratio);
+    OptionalFillPair readSolidFill(SWFStream& in, SWF::TagType t,
+            bool readMorph);
+    OptionalFillPair readBitmapFill(SWFStream& in, SWF::FillType type,
+            movie_definition& md, bool readMorph);
+    GradientRecord readGradientRecord(SWFStream& in, SWF::TagType tag);
+}
+
+namespace {
+
+/// Create a lerped version of two other FillStyles.
+//
+/// The two fill styles must have exactly the same types. Callers are 
+/// responsible for ensuring this.
+class SetLerp : public boost::static_visitor<>
+{
+public:
+    SetLerp(const FillStyle::Fill& a, const FillStyle::Fill& b, double ratio)
+        :
+        _a(a),
+        _b(b),
+        _ratio(ratio)
+    {
+    }
+
+    template<typename T> void operator()(T& f) const {
+        const T& a = boost::get<T>(_a);
+        const T& b = boost::get<T>(_b);
+        f.setLerp(a, b, _ratio);
+    }
+
+private:
+    const FillStyle::Fill& _a;
+    const FillStyle::Fill& _b;
+    const double _ratio;
+
+};
+
+}
+
+SWFMatrix
+gradientMatrix(GradientFill::Type t, const SWFMatrix& m)
+{
+    SWFMatrix base;
+    switch (t) {
+        case GradientFill::LINEAR:
+            base.set_translation(128, 0);
+            base.set_scale(1.0 / 128, 1.0 / 128);
+            break;
+        case GradientFill::RADIAL:
+            base.set_translation(32, 32);
+            base.set_scale(1.0 / 512, 1.0 / 512);
+            break;
+    }
+    base.concatenate(m);
+    return base;
+}
+
+GradientFill::GradientFill(Type t, const SWFMatrix& m,
+        const GradientRecords& recs)
+    :
+    spreadMode(SWF::GRADIENT_SPREAD_PAD),
+    interpolation(SWF::GRADIENT_INTERPOLATION_NORMAL),
+    _focalPoint(0.0),
+    _gradients(recs),
+    _type(t),
+    _matrix(gradientMatrix(t, m))
+{
+    assert(recs.empty() || recs.size() > 1);
+}
+    
 void
-gradient_record::read(SWFStream& in, SWF::TagType tag)
+GradientFill::setFocalPoint(double d)
 {
-    in.ensureBytes(1);
-    m_ratio = in.read_u8();
-    m_color.read(in, tag);
+    _focalPoint = clamp<float>(d, -1, 1); 
 }
-
-fill_style::fill_style()
+    
+BitmapFill::BitmapFill(SWF::FillType t, movie_definition* md,
+        boost::uint16_t id, const SWFMatrix& m)
     :
+    _type(),
+    _smoothingPolicy(),
+    _matrix(m),
     _bitmapInfo(0),
-    m_color(), 
-    m_spread_mode(SWF::GRADIENT_SPREAD_PAD),
-    m_interpolation(SWF::GRADIENT_INTERPOL_NORMAL),
-    m_type(SWF::FILL_SOLID),
-    _bitmapSmoothingPolicy(BITMAP_SMOOTHING_UNSPECIFIED)
-{
-}
-
-void
-fill_style::read(SWFStream& in, SWF::TagType t, movie_definition& md,
-        const RunResources& r, fill_style *pOther)
-{
-    const bool is_morph = (pOther != NULL);
+    _md(md),
+    _id(id)
+{
+    assert(md);
+
+    _smoothingPolicy = md->get_version() >= 8 ? 
+        BitmapFill::SMOOTHING_ON : BitmapFill::SMOOTHING_UNSPECIFIED;
+
+    switch (t) {
+        case SWF::FILL_TILED_BITMAP_HARD:
+            _type = BitmapFill::TILED;
+            _smoothingPolicy = BitmapFill::SMOOTHING_OFF;
+            break;
+
+        case SWF::FILL_TILED_BITMAP:
+            _type = BitmapFill::TILED;
+            break;
+
+        case SWF::FILL_CLIPPED_BITMAP_HARD:
+            _type = BitmapFill::CLIPPED;
+            _smoothingPolicy = BitmapFill::SMOOTHING_OFF;
+            break;
+
+        case SWF::FILL_CLIPPED_BITMAP:
+            _type = BitmapFill::CLIPPED;
+            break;
+
+        default:
+            std::abort();
+    }
+}
+
+const BitmapInfo*
+BitmapFill::bitmap() const
+{
+    if (_bitmapInfo) return _bitmapInfo.get();
+    if (!_md) return 0;
+    _bitmapInfo = _md->getBitmap(_id);
+
+    // May still be 0!
+    return _bitmapInfo.get();
+}
+    
+void
+GradientFill::setLerp(const GradientFill& a, const GradientFill& b,
+        double ratio)
+{
+    assert(type() == a.type());
+    assert(_gradients.size() == a.recordCount());
+    assert(_gradients.size() == b.recordCount());
+
+    for (size_t i = 0, e = _gradients.size(); i < e; ++i) {
+        const GradientRecord& ra = a.record(i);
+        const GradientRecord& rb = b.record(i);
+        _gradients[i].ratio = frnd(lerp<float>(ra.ratio, rb.ratio, ratio));
+        _gradients[i].color.set_lerp(ra.color, rb.color, ratio);
+    }
+    _matrix.set_lerp(a.matrix(), b.matrix(), ratio);
+}
+    
+void
+BitmapFill::setLerp(const BitmapFill& a, const BitmapFill& b, double ratio)
+{
+    _matrix.set_lerp(a.matrix(), b.matrix(), ratio);
+}
+
+OptionalFillPair
+readFills(SWFStream& in, SWF::TagType t, movie_definition& md, bool readMorph)
+{
 
     in.ensureBytes(1);
-    m_type = in.read_u8();
-    if (is_morph)
-    {
-        pOther->m_type = m_type;
-    }
+    const SWF::FillType type = static_cast<SWF::FillType>(in.read_u8());
         
     IF_VERBOSE_PARSE(
-        log_parse("  fill_style read type = 0x%X", (int)m_type);
+        log_parse("  FillStyle read type = 0x%X", +type);
     );
 
-    if (m_type == SWF::FILL_SOLID)
-    {
-        // 0x00: solid fill
-        if (t == SWF::DEFINESHAPE3 || t == SWF::DEFINESHAPE4
-            || t == SWF::DEFINESHAPE4_ || is_morph) {
-
-            m_color.read_rgba(in);
-            if (is_morph)   pOther->m_color.read_rgba(in);
-        }
-        else {
-            // For DefineMorphShape tags we should use morph_fill_style 
-            assert(t == SWF::DEFINESHAPE || t == SWF::DEFINESHAPE2);
-            m_color.read_rgb(in);
-        }
-
-        IF_VERBOSE_PARSE(
-            log_parse("  color: %s", m_color);
-        );
-    }
-    else if (m_type == SWF::FILL_LINEAR_GRADIENT
-            || m_type == SWF::FILL_RADIAL_GRADIENT
-            || m_type == SWF::FILL_FOCAL_GRADIENT)
-    {
-        // 0x10: linear gradient fill
-        // 0x12: radial gradient fill
-        // 0x13: focal gradient fill
-
-        SWFMatrix  input_matrix;
-        input_matrix.read(in);
-
-        // shouldn't this be in initializer's list ?
-        _matrix.set_identity();
-        if (m_type == SWF::FILL_LINEAR_GRADIENT) {
-            _matrix.set_translation(128, 0);
-            _matrix.set_scale(1.0/128, 1.0/128);
-        }
-        else {
-            // FILL_RADIAL_GRADIENT or FILL_FOCAL_GRADIENT
-            _matrix.set_translation(32, 32);
-            _matrix.set_scale(1.0/512, 1.0/512);
-        }
-
-        SWFMatrix m = input_matrix;
-        m.invert();
-
-        if (is_morph) pOther->_matrix = _matrix;
-        _matrix.concatenate(m);
-        
-        if (is_morph) {
-            input_matrix.read(in);
-            m = input_matrix;
-            m.invert();
-            pOther->_matrix.concatenate(m);
-        }
-        
-        // GRADIENT
-        in.ensureBytes(1);
-
-        boost::uint8_t grad_props = in.read_u8();
-    
-        if (t == SWF::DEFINESHAPE4 ||
-            t == SWF::DEFINESHAPE4_) {
-            boost::uint8_t spread_mode = grad_props >> 6;
-            switch(spread_mode) {
-                case 0:
-                    m_spread_mode = SWF::GRADIENT_SPREAD_PAD;
-                    break;
-                case 1:
-                    m_spread_mode = SWF::GRADIENT_SPREAD_REFLECT;
-                    break;
-                case 2:
-                    m_spread_mode = SWF::GRADIENT_SPREAD_REPEAT;
-                    break;
-                default: 
+    switch (type) {
+
+        case SWF::FILL_SOLID:
+            return readSolidFill(in, t, readMorph);
+
+        case SWF::FILL_TILED_BITMAP_HARD:
+        case SWF::FILL_CLIPPED_BITMAP_HARD:
+        case SWF::FILL_TILED_BITMAP:
+        case SWF::FILL_CLIPPED_BITMAP:
+            return readBitmapFill(in, type, md, readMorph);
+
+        case SWF::FILL_LINEAR_GRADIENT:
+        case SWF::FILL_RADIAL_GRADIENT:
+        case SWF::FILL_FOCAL_GRADIENT:
+        {
+
+            GradientFill::Type gr;
+            switch (type) {
+                case SWF::FILL_LINEAR_GRADIENT:
+                    gr = GradientFill::LINEAR;
+                    break;
+                case SWF::FILL_RADIAL_GRADIENT:
+                case SWF::FILL_FOCAL_GRADIENT:
+                    gr = GradientFill::RADIAL;
+                    break;
+                default:
+                    std::abort();
+            }
+
+            SWFMatrix m = readSWFMatrix(in).invert();
+            GradientFill gf(gr, m);
+
+            boost::optional<FillStyle> morph;
+            if (readMorph) {
+                SWFMatrix m2 = readSWFMatrix(in).invert();
+                morph = GradientFill(gr, m2);
+            }
+            
+            in.ensureBytes(1);
+            const boost::uint8_t grad_props = in.read_u8();
+            
+            const boost::uint8_t num_gradients = grad_props & 0xF;
+            IF_VERBOSE_PARSE(
+               log_parse("  gradients: num_gradients = %d", +num_gradients);
+            );
+        
+            if (!num_gradients) {
                 IF_VERBOSE_MALFORMED_SWF(
-                    log_swferror("Illegal spread mode in gradient 
definition.");
-                );
-            }
-    
-            boost::uint8_t interpolation = (grad_props >> 4) & 3;
-            switch(interpolation) {
-                case 0: 
-                    m_interpolation = SWF::GRADIENT_INTERPOL_NORMAL;
-                    break;
-                case 1:
-                    m_interpolation = SWF::GRADIENT_INTERPOL_LINEAR;
-                    break;
-                default:
-                    IF_VERBOSE_MALFORMED_SWF(
-                        log_swferror("Illegal interpolation mode in gradient "
-                            "definition.");
-                    );
-            }
-        }
-    
-        boost::uint8_t num_gradients = grad_props & 0xF;
-        if (!num_gradients) {
-            IF_VERBOSE_MALFORMED_SWF(
-                log_swferror(_("num gradients 0"));
-            );
-            return;
-        }
-    
-        if (num_gradients > 8 + ((t == SWF::DEFINESHAPE4 ||
-            t == SWF::DEFINESHAPE4_) ? 7 : 0)) {
-           // see: http://sswf.sourceforge.net/SWFalexref.html#swf_gradient
-            IF_VERBOSE_MALFORMED_SWF(
-                log_swferror(_("Unexpected num gradients (%d), "
-                        "expected 1 to 8"), static_cast<int>(num_gradients));
-            );
-        }
-    
-        if (is_morph) {
-            pOther->m_gradients.resize(num_gradients);
-        }
-                
-        m_gradients.resize(num_gradients);
-        for (size_t i = 0; i < num_gradients; ++i) {
-            m_gradients[i].read(in, t);
-            if (is_morph) {
-                pOther->m_gradients[i].read(in, t);
-            }
-        }
-    
-        // A focal gradient also has a focal point.
-        if (m_type == SWF::FILL_FOCAL_GRADIENT) {
-           in.ensureBytes(2);
-           m_focal_point = in.read_short_sfixed();
-           if (m_focal_point < -1.0f) m_focal_point = -1.0f;
-           else if (m_focal_point > 1.0f) m_focal_point = 1.0f;
-        }
-    
-        if (is_morph) {
-                pOther->m_focal_point = m_focal_point;
-        }
-    
-        IF_VERBOSE_PARSE(
-           log_parse("  gradients: num_gradients = %d",
-               static_cast<int>(num_gradients));
-        );
-    
-        // @@ hack. What is it supposed to do?
-        if (num_gradients > 0) {
-            m_color = m_gradients[0].m_color;
-            if (is_morph)
-               pOther->m_color = pOther->m_gradients[0].m_color;
-        }
-    
-        Renderer* renderer = r.renderer();
-        if (renderer) {
-
-            _bitmapInfo = create_gradient_bitmap(*renderer);
-            if (is_morph) {
-                pOther->_bitmapInfo = pOther->need_gradient_bitmap(*renderer);
-            }
-        }
-    }
-    else if (m_type == SWF::FILL_TILED_BITMAP
-          || m_type == SWF::FILL_CLIPPED_BITMAP
-          || m_type == SWF::FILL_TILED_BITMAP_HARD
-          || m_type == SWF::FILL_CLIPPED_BITMAP_HARD)
-    {
-        // 0x40: tiled bitmap fill
-        // 0x41: clipped bitmap fill
-        // 0x42: tiled bitmap fill with hard edges
-        // 0x43: clipped bitmap fill with hard edges
-
-        if (m_type == SWF::FILL_TILED_BITMAP_HARD ||
-             m_type == SWF::FILL_CLIPPED_BITMAP_HARD) {
-            _bitmapSmoothingPolicy = BITMAP_SMOOTHING_OFF;
-        }
-        else if (md.get_version() >= 8) {
-            _bitmapSmoothingPolicy = BITMAP_SMOOTHING_ON;
-        }
-        else {
-            _bitmapSmoothingPolicy = BITMAP_SMOOTHING_UNSPECIFIED;
-        }
-
-        in.ensureBytes(2);
-        int bitmap_char_id = in.read_u16();
-        IF_VERBOSE_PARSE(
-            log_parse("  bitmap_char = %d, smoothing_policy = %s",
-                bitmap_char_id, _bitmapSmoothingPolicy);
-        );
-
-        // Look up the bitmap DisplayObject.
-        _bitmapInfo = md.getBitmap(bitmap_char_id);
-        IF_VERBOSE_MALFORMED_SWF(
-            if (!_bitmapInfo) {
-                LOG_ONCE(
-                    log_swferror(_("Bitmap fill specifies '%d' as associated"
-                        " bitmap DisplayObject id,"
-                        " but that DisplayObject is not found"
-                        " in the Characters Dictionary."
-                        " It seems common to find such "
-                        " malformed SWF, so we'll only warn once "
-                        "about this."), bitmap_char_id);
-                );
-            }
-        );
-
-        SWFMatrix m;
-        m.read(in);
-
-        // For some reason, it looks like they store the inverse of the
-        // TWIPS-to-texcoords SWFMatrix.
-        _matrix = m.invert();
-
-        if (is_morph) {
-            pOther->_bitmapInfo = _bitmapInfo;
-            m.read(in);
-            pOther->_matrix = m.invert();
-        }
-
-        IF_VERBOSE_PARSE(
-           log_parse("SWFMatrix: %s", _matrix);
-        );
-    }
-    else {
-        std::stringstream ss;
-        ss << "Unknown fill style type " << m_type;    
-        // This is a fatal error, we'll be leaving the stream
-        // read pointer in an unknown position.
-        throw ParserException(ss.str()); 
-    }
-}
-
-
-const BitmapInfo* 
-fill_style::get_bitmap_info(Renderer& renderer) const 
-{    
-    assert(m_type != SWF::FILL_SOLID);
-
-    switch (m_type)
-    {
-        case SWF::FILL_TILED_BITMAP:
-        case SWF::FILL_CLIPPED_BITMAP:
-        case SWF::FILL_TILED_BITMAP_HARD:
-        case SWF::FILL_CLIPPED_BITMAP_HARD:
-            if (_bitmapInfo)
-            {
-                return _bitmapInfo.get();
-            }
-            return NULL;
-   
-        case SWF::FILL_LINEAR_GRADIENT:
-        case SWF::FILL_RADIAL_GRADIENT:
-            return need_gradient_bitmap(renderer);
+                    log_swferror(_("No gradients!"));
+                );
+                throw ParserException();
+            }
+        
+            GradientFill::GradientRecords recs;
+            recs.reserve(num_gradients);
+
+            GradientFill::GradientRecords morphrecs;
+            morphrecs.reserve(num_gradients);
+
+            for (size_t i = 0; i < num_gradients; ++i) {
+                recs.push_back(readGradientRecord(in, t));
+                if (readMorph) {
+                    morphrecs.push_back(readGradientRecord(in, t));
+                }
+            }
+        
+            // A GradientFill may never have fewer than 2 colour stops. We've
+            // no tests to show what happens in that case for static fills.
+            // Dynamic fills are tested to display as a solid fill. In either
+            // case the renderer will bork if there is only 1 stop in a 
+            // GradientFill.
+            if (num_gradients == 1) {
+                const rgba c1 = recs[0].color;
+                if (readMorph) {
+                    const rgba c2 = morphrecs[0].color;
+                    morph = SolidFill(c2);
+                }
+                return std::make_pair(SolidFill(c1), morph);
+            }
+        
+            gf.setRecords(recs);
+            if (readMorph) {
+                boost::get<GradientFill>(morph->fill).setRecords(morphrecs);
+            }
+
+
+            if (t == SWF::DEFINESHAPE4 || t == SWF::DEFINESHAPE4_) {
+
+                const SWF::SpreadMode spread =
+                    static_cast<SWF::SpreadMode>(grad_props >> 6);
+
+                switch (spread) {
+                    case SWF::GRADIENT_SPREAD_PAD:
+                    case SWF::GRADIENT_SPREAD_REFLECT:
+                    case SWF::GRADIENT_SPREAD_REPEAT:
+                        gf.spreadMode = spread;
+                        break;
+                    default: 
+                        IF_VERBOSE_MALFORMED_SWF(
+                            log_swferror("Illegal spread mode in gradient "
+                                "definition.");
+                        );
+                }
+        
+                // TODO: handle in GradientFill.
+                const SWF::InterpolationMode i =
+                    static_cast<SWF::InterpolationMode>((grad_props >> 4) & 3);
+
+                switch (i) {
+                    case SWF::GRADIENT_INTERPOLATION_NORMAL:
+                    case SWF::GRADIENT_INTERPOLATION_LINEAR:
+                        gf.interpolation = i;
+                    default:
+                        IF_VERBOSE_MALFORMED_SWF(
+                            log_swferror("Illegal interpolation mode in "
+                                "gradient definition.");
+                        );
+                }
+            }
+
+            // A focal gradient also has a focal point.
+            if (type == SWF::FILL_FOCAL_GRADIENT) {
+               in.ensureBytes(2);
+               gf.setFocalPoint(in.read_short_sfixed());
+            }
+        
+            if (readMorph) {
+                boost::get<GradientFill>(morph->fill).
+                    setFocalPoint(gf.focalPoint());
+            }
+
+            return std::make_pair(gf, morph);
+        }
+
         default:
-            log_error(_("Unknown fill style %d"), m_type);
-            // Seems a bit drastic...
-            std::abort();
-    }
-}
-
-const SWFMatrix&
-fill_style::getBitmapMatrix() const 
-{
-  assert(m_type != SWF::FILL_SOLID);
-  return _matrix;
-}
-
-const SWFMatrix&
-fill_style::getGradientMatrix() const 
-{
-  // TODO: Why do we separate bitmap and gradient matrices? 
-  return _matrix;
-}
-
-rgba
-fill_style::sample_gradient(boost::uint8_t ratio) const
-{
-    assert(m_type == SWF::FILL_LINEAR_GRADIENT
-        || m_type == SWF::FILL_RADIAL_GRADIENT
-        || m_type == SWF::FILL_FOCAL_GRADIENT);
-
-    if (m_gradients.empty()) {
-        static const rgba black;
-        return black;
-    }
-
-    // By specs, first gradient should *always* be 0, 
-    // anyway a malformed SWF could break this,
-    // so we cannot rely on that information...
-    if (ratio < m_gradients[0].m_ratio)
-    {
-        IF_VERBOSE_MALFORMED_SWF(
-            LOG_ONCE(
-                log_swferror(
-                    _("First gradient in a fill_style "
-                    "have position==%d (expected 0)."
-                    " This seems to be common, so will"
-                    " warn only once."),
-                    static_cast<int>(m_gradients[0].m_ratio));
-            );
-        );
-        return m_gradients[0].m_color;
-    }
-
-    if (ratio >= m_gradients.back().m_ratio)
-    {
-        return m_gradients.back().m_color;
-    }
-        
-    for (size_t i = 1, n = m_gradients.size(); i < n; ++i)
-    {
-        const gradient_record& gr1 = m_gradients[i];
-        if (gr1.m_ratio < ratio) continue;
-
-        const gradient_record& gr0 = m_gradients[i - 1];
-        if (gr0.m_ratio > ratio) continue;
-
-        float f = 0.0f;
-
-        if ( gr0.m_ratio != gr1.m_ratio )
-        {
-            f = (ratio - gr0.m_ratio) / float(gr1.m_ratio - gr0.m_ratio);
-        }
-        else
-        {
-            // Ratios are equal IFF first and second gradient_record
-            // have the same ratio. This would be a malformed SWF.
-            IF_VERBOSE_MALFORMED_SWF(
-                log_swferror(
-                    _("two gradients in a fill_style "
-                    "have the same position/ratio: %d"),
-                    gr0.m_ratio);
-            );
-        }
-
-        rgba result;
-        result.set_lerp(gr0.m_color, gr1.m_color, f);
-        return result;
-    }
-
-    // Assuming gradients are ordered by m_ratio? see start comment
-    return m_gradients.back().m_color;
-}
-
-const BitmapInfo*
-fill_style::create_gradient_bitmap(Renderer& renderer) const
-{
-    assert(m_type == SWF::FILL_LINEAR_GRADIENT
-        || m_type == SWF::FILL_RADIAL_GRADIENT
-        || m_type == SWF::FILL_FOCAL_GRADIENT);
-
-    std::auto_ptr<ImageRGBA> im;
-
-    switch (m_type)
-    {
-        case SWF::FILL_LINEAR_GRADIENT:
-            // Linear gradient.
-            im.reset(new ImageRGBA(256, 1));
-
-            for (size_t i = 0; i < im->width(); i++) {
-                rgba sample = sample_gradient(i);
-                im->setPixel(i, 0, sample.m_r, sample.m_g,
-                        sample.m_b, sample.m_a);
-            }
-            break;
-
-        case SWF::FILL_RADIAL_GRADIENT:
-            // Radial gradient.
-            im.reset(new ImageRGBA(64, 64));
-
-            for (size_t j = 0; j < im->height(); j++) {
-                for (size_t i = 0; i < im->width(); i++) {
-                    float radius = (im->height() - 1) / 2.0f;
-                    float y = (j - radius) / radius;
-                    float x = (i - radius) / radius;
-                    int ratio = static_cast<int>(
-                            std::floor(255.5f * std::sqrt(x * x + y * y)));
-                    if (ratio > 255) {
-                        ratio = 255;
-                    }
-                    rgba sample = sample_gradient(ratio);
-                    im->setPixel(i, j, sample.m_r, sample.m_g,
-                            sample.m_b, sample.m_a);
-                }
-            }
-            break;
-
-        case SWF::FILL_FOCAL_GRADIENT:
-            // Focal gradient.
-            im.reset(new ImageRGBA(64, 64));
-
-            for (size_t j = 0; j < im->height(); j++)
-            {
-                for (size_t i = 0; i < im->width(); i++)
-                {
-                    float radiusy = (im->height() - 1) / 2.0f;
-                    float radiusx = radiusy + std::abs(radiusy * 
m_focal_point);
-                    float y = (j - radiusy) / radiusy;
-                    float x = (i - radiusx) / radiusx;
-                    int ratio = static_cast<int>(std::floor(255.5f *
-                                std::sqrt(x*x + y*y)));
-                    
-                    if (ratio > 255) ratio = 255;
-
-                    rgba sample = sample_gradient(ratio);
-                    im->setPixel(i, j, sample.m_r, sample.m_g,
-                            sample.m_b, sample.m_a);
-                }
-            }
-            break;
-    }
-
-    const BitmapInfo* bi = renderer.createBitmapInfo(
-                    static_cast<std::auto_ptr<GnashImage> >(im));
-
-    return bi;
-}
-
-
-const BitmapInfo*
-fill_style::need_gradient_bitmap(Renderer& renderer) const 
-{
-
-  if (!_bitmapInfo) {
-    fill_style* this_non_const = const_cast<fill_style*>(this);
-    this_non_const->_bitmapInfo = create_gradient_bitmap(renderer);
-  }
-  
-  return _bitmapInfo.get();
-
-}
-
+        {
+            std::stringstream ss;
+            ss << "Unknown fill style type " << +type;    
+            // This is a fatal error, we'll be leaving the stream
+            // read pointer in an unknown position.
+            throw ParserException(ss.str()); 
+        }
+    }
+}
 
 // Sets this style to a blend of a and b.  t = [0,1]
 void
-fill_style::set_lerp(const fill_style& a, const fill_style& b, float t)
+setLerp(FillStyle& f, const FillStyle& a, const FillStyle& b, double t)
 {
     assert(t >= 0 && t <= 1);
-
-    // fill style type
-    m_type = a.get_type();
-    assert(m_type == b.get_type());
-
-    // fill style color (TODO: only for solid fills ?)
-    m_color.set_lerp(a.get_color(), b.get_color(), t);
-
-    bool usesMatrix = false;
-
-    switch (m_type)
-    {
-        case SWF::FILL_LINEAR_GRADIENT:
-        case SWF::FILL_RADIAL_GRADIENT:
-        case SWF::FILL_FOCAL_GRADIENT:
-        {
-            usesMatrix = true;
-
-            // fill style gradients
-            assert(m_gradients.size() == a.m_gradients.size());
-            assert(m_gradients.size() == b.m_gradients.size());
-            for (size_t j=0, nj=m_gradients.size(); j<nj; ++j)
-            {
-                m_gradients[j].m_ratio =
-                    (boost::uint8_t) frnd( flerp(a.m_gradients[j].m_ratio,
-                            b.m_gradients[j].m_ratio, t)
-                        );
-                m_gradients[j].m_color.set_lerp(a.m_gradients[j].m_color,
-                        b.m_gradients[j].m_color, t);
-            }
-            _bitmapInfo = NULL;
-            break;
-        }
-
-        case SWF::FILL_TILED_BITMAP:
-        case SWF::FILL_CLIPPED_BITMAP:
-        case SWF::FILL_TILED_BITMAP_HARD:
-        case SWF::FILL_CLIPPED_BITMAP_HARD:
-        {
-            usesMatrix = true;
-
-            // fill style bitmap ID
-            _bitmapInfo = a._bitmapInfo;
-            assert(_bitmapInfo == b._bitmapInfo);
-            break;
-        }
-
+    f.fill = a.fill;
+    boost::apply_visitor(SetLerp(a.fill, b.fill, t), f.fill);
+}
+
+namespace {
+
+OptionalFillPair
+readSolidFill(SWFStream& in, SWF::TagType t, bool readMorph)
+{
+    rgba color;
+
+    boost::optional<FillStyle> morph;
+
+    // 0x00: solid fill
+    if (t == SWF::DEFINESHAPE3 || t == SWF::DEFINESHAPE4 ||
+            t == SWF::DEFINESHAPE4_ || readMorph) {
+        color = readRGBA(in);
+        if (readMorph) {
+            rgba othercolor;
+            othercolor = readRGBA(in);
+            morph = SolidFill(othercolor);
+        }
+    }
+    else {
+        // For DefineMorphShape tags we should use morphFillStyle 
+        assert(t == SWF::DEFINESHAPE || t == SWF::DEFINESHAPE2);
+        color = readRGB(in);
+    }
+
+    IF_VERBOSE_PARSE(
+        log_parse("  color: %s", color);
+    );
+    return std::make_pair(SolidFill(color), morph);
+}
+
+OptionalFillPair
+readBitmapFill(SWFStream& in, SWF::FillType type, movie_definition& md,
+        bool readMorph)
+{
+
+    in.ensureBytes(2);
+    const boost::uint16_t id = in.read_u16();
+
+    SWFMatrix m = readSWFMatrix(in).invert();
+
+    boost::optional<FillStyle> morph;
+    if (readMorph) {
+        SWFMatrix m2 = readSWFMatrix(in).invert();
+        morph = BitmapFill(type, &md, id, m2);
+    }
+
+    // For some reason, it looks like they store the inverse of the
+    // TWIPS-to-texcoords SWFMatrix.
+    return std::make_pair(BitmapFill(type, &md, id, m), morph);
+}
+
+GradientRecord
+readGradientRecord(SWFStream& in, SWF::TagType tag)
+{
+    in.ensureBytes(1);
+    const boost::uint8_t ratio = in.read_u8();
+
+    switch (tag) {
+        case SWF::DEFINESHAPE:
+        case SWF::DEFINESHAPE2:
+        {
+            const rgba color = readRGB(in);
+            return GradientRecord(ratio, color);
+        }
         default:
             break;
     }
-
-    // fill style bitmap or gradient SWFMatrix
-    if (usesMatrix) _matrix.set_lerp(a._matrix, b._matrix, t);
-}
-
-
-size_t
-fill_style::get_color_stop_count() const 
-{
-    return m_gradients.size();
-}
-
-const gradient_record& 
-fill_style::get_color_stop(size_t index) const
-{
-    assert(index < m_gradients.size());
-    return m_gradients[index];
-}
-
-fill_style::fill_style(const BitmapInfo* const bitmap, const SWFMatrix& mat)
-    :
-    _matrix(mat),
-    _bitmapInfo(bitmap),
-    m_type(SWF::FILL_CLIPPED_BITMAP),
-    _bitmapSmoothingPolicy(BITMAP_SMOOTHING_UNSPECIFIED)
-{
-}
-
-void
-fill_style::setSolid(const rgba& color)
-{
-    m_type = SWF::FILL_SOLID;
-    m_color = color;
-    _bitmapInfo = 0;
-}
-
-void
-fill_style::setLinearGradient(const std::vector<gradient_record>& gradients,
-        const SWFMatrix& mat)
-{
-
-    assert(!gradients.empty());
-    
-    // We must ensure that all gradients have more than one colour stop
-    // because asking renderers to render a gradient with one colour
-    // can cause them to invoke UB.
-    if (gradients.size() < 2) {
-        setSolid(gradients[0].m_color);
-        return;
-    }
-
-    m_type = SWF::FILL_LINEAR_GRADIENT;
-    m_gradients = gradients;
-
-    _matrix = mat;
-    _bitmapInfo = 0;
-}
-
-void
-fill_style::setRadialGradient(const std::vector<gradient_record>& gradients,
-        const SWFMatrix& mat)
-{
-    assert(!gradients.empty());
-    
-    // We must ensure that all gradients have more than one colour stop
-    // because asking renderers to render a gradient with one colour
-    // can cause them to invoke UB.
-    if (gradients.size() < 2) {
-        setSolid(gradients[0].m_color);
-        return;
-    }
-    
-    m_type = SWF::FILL_RADIAL_GRADIENT;
-    m_gradients = gradients;
-
-    _matrix = mat;
-    _bitmapInfo = 0;
-}
-
-std::ostream& operator << (std::ostream& os,
-        const fill_style::BitmapSmoothingPolicy& p)
-{
-    switch (p)
-    {
-        case fill_style::BITMAP_SMOOTHING_UNSPECIFIED:
+    const rgba color = readRGBA(in);
+    return GradientRecord(ratio, color);
+}
+
+} // anonymous namespace
+
+std::ostream&
+operator<<(std::ostream& os, const BitmapFill::SmoothingPolicy& p)
+{
+    switch (p) {
+        case BitmapFill::SMOOTHING_UNSPECIFIED:
             os << "unspecified";
             break;
-        case fill_style::BITMAP_SMOOTHING_ON:
+        case BitmapFill::SMOOTHING_ON:
             os << "on";
             break;
-        case fill_style::BITMAP_SMOOTHING_OFF:
+        case BitmapFill::SMOOTHING_OFF:
             os << "off";
             break;
         default:
             // cast to int required to avoid infinite recursion
-            os << "unknown " << (int)p;
+            os << "unknown " << +p;
             break;
     }
     return os;
 }
 
-} // end of namespace
+} // namespace gnash
 
 
 // Local Variables:

=== renamed file 'libcore/fill_style.h' => 'libcore/FillStyle.h'
--- a/libcore/fill_style.h      2010-07-12 21:18:16 +0000
+++ b/libcore/FillStyle.h       2010-08-01 06:17:17 +0000
@@ -15,22 +15,21 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-// Based on work of Thatcher Ulrich <address@hidden> 2003
-
-
 #ifndef GNASH_FILL_STYLE_H
 #define GNASH_FILL_STYLE_H
 
+#include <boost/variant.hpp>
+#include <vector> 
+#include <iosfwd> 
+#include <boost/optional.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <cassert>
+
 #include "SWFMatrix.h"
 #include "BitmapInfo.h"
 #include "SWF.h"
 #include "RGBA.h" // for rgba type
 
-#include <vector> // for composition
-#include <iosfwd> // for output operator forward declarations
-
-#include <boost/intrusive_ptr.hpp>
-
 namespace gnash {
 
 class SWFStream;
@@ -38,240 +37,289 @@
 class Renderer;
 class RunResources;
 
-class gradient_record
+class GradientRecord
 {
 public:
-    gradient_record()
-        :
-        m_ratio(0),
-        m_color()
-    {}
-
-    gradient_record(boost::uint8_t ratio, const rgba& color)
-        :
-        m_ratio(ratio),
-        m_color(color)
-    {}
-
-    void read(SWFStream& in, SWF::TagType tag);
+
+    GradientRecord(boost::uint8_t ratio, const rgba& color)
+        :
+        ratio(ratio),
+        color(color)
+    {}
     
     //data:
-    boost::uint8_t m_ratio;
-    rgba m_color;
-};
-
-
-/// For the interior of outline shapes.
-class DSOEXPORT fill_style 
-{
-public:
-
-    /// Bitmap smoothing policy
-    enum BitmapSmoothingPolicy {
-
-        /// Only smooth when _quality >= BEST
-        //
-        /// This is the policy for bitmap fills
-        /// defined by SWF up to version 7:
-        ///  - SWF::FILL_CLIPPED_BITMAP
-        ///  - SWF::FILL_TILED_BITMAP
-        ///
-        BITMAP_SMOOTHING_UNSPECIFIED,
-
-        /// Always smooth if _quality > LOW
-        //
-        /// This is the policy for non-hard bitmap fills
-        /// defined by SWF 8 and higher:
-        ///  - SWF::FILL_CLIPPED_BITMAP
-        ///  - SWF::FILL_TILED_BITMAP
-        ///
-        BITMAP_SMOOTHING_ON,
-
-        /// Never smooth
-        ///
-        /// MovieClip.forceSmoothing can force this to
-        /// behave like BITMAP_SMOOTHING_ON 
-        ///
-        /// This is the policy for hard bitmap fills
-        /// introduced in SWF 8:
-        ///  - SWF::FILL_CLIPPED_BITMAP_HARD
-        ///  - SWF::FILL_TILED_BITMAP_HARD
-        ///
-        ///
-        BITMAP_SMOOTHING_OFF
-    };
-    
-
-    /// Create a solid opaque white fill.
-    fill_style();
-
-    /// Construct a clipped bitmap fill style, for
-    /// use by bitmap shape DisplayObject.
-    ///
-    /// TODO: use a subclass for this
-    /// TODO: provide a setBitmap, for consisteny with other setType() methods
-    ///
-    /// @param bitmap
-    ///    The bitmap DisplayObject definition to use with this bitmap fill.
-    ///
-    /// @param mat
-    ///    The SWFMatrix to apply to the bitmap.
-    ///
-    fill_style(const BitmapInfo* const bitmap, const SWFMatrix& mat);
-
-    ~fill_style() {}
-
-    /// Turn this fill style into a solid fill.
-    //
-    /// This is used for dynamic gradient generation.
-    //
-    void setSolid(const rgba& color);
-
-    /// Turn this fill style into a linear gradient
-    //
-    /// This is used for dynamic gradient generation.
-    //
-    /// Note: passing only one gradient record will result in a solid fill
-    /// style, not a gradient. This is for compatibility with dynamic
-    /// fill style generation.
-    //
-    /// @param gradients    Gradient records.
-    /// @param mat          Gradient SWFMatrix.
-    void setLinearGradient(const std::vector<gradient_record>& gradients, 
-            const SWFMatrix& mat);
-
-    /// Turn this fill style into a radial gradient
-    //
-    /// This is used for dynamic gradient generation.
-    //
-    /// Note: passing only one gradient record will result in a solid fill
-    /// style, not a gradient. This is for compatibility with dynamic
-    /// fill style generation.
-    //
-    /// @param gradients    Gradient records.
-    /// @param mat          Gradient SWFMatrix.
-    void setRadialGradient(const std::vector<gradient_record>& gradients,
-            const SWFMatrix& mat);
-    
-    /// Read the fill style from a stream
-    //
-    /// TODO: use a subclass for this (swf_fill_style?)
-    ///
-    /// Throw a ParserException if there's no enough bytes in the
-    /// currently opened tag for reading. See stream::ensureBytes()
-    void read(SWFStream& in, SWF::TagType t, movie_definition& m,
-            const RunResources& r, fill_style *pOther = 0);
-
-    /// \brief
-    /// Make a BitmapInfo* corresponding to our gradient.
-    /// We can use this to set the gradient fill style.
-    const BitmapInfo* create_gradient_bitmap(Renderer& renderer) const;
-    
-    /// \brief
-    /// Makes sure that _gradientBitmapInfo is not NULL. Calls 
-    /// create_gradient_bitmap() if necessary and returns _gradientBitmapInfo.
-    const BitmapInfo* need_gradient_bitmap(Renderer& renderer) const; 
-    
-    rgba get_color() const {
-        return m_color;
-    }
-
-    void set_color(rgba new_color) {
-        m_color = new_color;
-    }
-
-    /// Get fill type, see SWF::fill_style_type
-    boost::uint8_t get_type() const {
-        return m_type;
-    }
-
-    SWF::gradient_spread_mode get_gradient_spread_mode() const {
-        return m_spread_mode;
-    }
-
-    SWF::gradient_interpolation_mode get_gradient_interpolation_mode() const {
-        return m_interpolation;
-    }
-    
-    /// Sets this style to a blend of a and b.  t = [0,1] (for shape morphing)
-    void set_lerp(const fill_style& a, const fill_style& b, float t);
-    
-    /// Returns the bitmap info for all styles except solid fills
-    //
-    /// NOTE: calling this method against a solid fill style will
-    ///       result in a failed assertion.
-    /// 
-    /// NOTE2: this function can return NULL if the DisplayObject_id
-    ///        specified for the style in the SWF does not resolve
-    ///        to a DisplayObject defined in the DisplayObjects dictionary.
-    ///        (it happens..)
-    ///
-    const BitmapInfo* get_bitmap_info(Renderer& renderer) const;
-
-    BitmapSmoothingPolicy getBitmapSmoothingPolicy() const {
-        return _bitmapSmoothingPolicy;
-    }
-    
-    /// Returns the bitmap transformation SWFMatrix
-    const SWFMatrix& getBitmapMatrix() const; 
-    
-    /// Returns the gradient transformation SWFMatrix
-    const SWFMatrix& getGradientMatrix() const; 
-    
-    /// Returns the number of color stops in the gradient
-    size_t get_color_stop_count() const;
-    
-    /// Returns the color stop value at a specified index
-    const gradient_record& get_color_stop(size_t index) const;
-
-    /// Get and set the focal point for gradient focal fills.
-    /// This should be from -1.0 to 1.0, representing the left
-    /// and right edges of the rectangle.
-    float get_focal_point() const { return m_focal_point; }
-    void set_focal_point(float f) { m_focal_point = f; }
-
-private:
-
-    /// Return the color at the specified ratio into our gradient.
-    //
-    /// @param ratio
-    ///    Ratio is in the range [0, 255].
-    rgba sample_gradient(boost::uint8_t ratio) const;
-
-    // For BITMAP or GRADIENT types 
-    SWFMatrix _matrix;
-
-    // For BITMAP or GRADIENT types
-    boost::intrusive_ptr<const BitmapInfo> _bitmapInfo;
-
-    // For SOLID type (and arguably GRADIENT too)
-    rgba m_color;
-
-    // Only for GRADIENT type
-    float m_focal_point; // For focal fill gradients.
-    std::vector<gradient_record> m_gradients;
-    SWF::gradient_spread_mode m_spread_mode;
-    SWF::gradient_interpolation_mode m_interpolation;
-
-    /// Fill type, see SWF::fill_style_type
-    boost::uint8_t m_type;
-
-    // Only for BITMAP type
-    //
-    // 0: unspecified (smooth with _quality >= BEST)
-    // 1: smooth (smooth with _quality >= MEDIUM)
-    // 2: don't smooth, can be forced with .forceSmoothing, in
-    //    which case it becomes as policy 1
-    BitmapSmoothingPolicy _bitmapSmoothingPolicy;
-};
-
-DSOEXPORT std::ostream& operator << (std::ostream& os,
-    const fill_style::BitmapSmoothingPolicy& p);
+    boost::uint8_t ratio;
+    rgba color;
+};
+
+
+/// A BitmapFill
+//
+/// BitmapFills can refer to a parsed bitmap tag or be constructed from
+/// bitmap data. They are used for Bitmap characters.
+//
+/// Presently all members are immutable after construction. It is of course
+/// possible to change the appearance of the fill by changing the BitmapInfo
+/// it refers to.
+//
+/// TODO: check the following:
+//
+/// It may be necessary to allow setting the smoothing policy; the use of
+/// this should certainly be extended to non-static BitmapFills.
+class DSOEXPORT BitmapFill
+{
+public:
+
+    /// How to smooth the bitmap.
+    enum SmoothingPolicy {
+        SMOOTHING_UNSPECIFIED,
+        SMOOTHING_ON,
+        SMOOTHING_OFF
+    };
+    
+    /// Whether the fill is tiled or clipped.
+    //
+    /// Clipped fills use the edge pixels to fill any area outside the bounds
+    /// of the image.
+    enum Type {
+        CLIPPED,
+        TILED
+    };
+
+    /// Construct a BitmapFill from arbitrary bitmap data.
+    //
+    /// TODO: check the smoothing policy here!
+    BitmapFill(Type t, const BitmapInfo* bi, const SWFMatrix& m)
+        :
+        _type(t),
+        _smoothingPolicy(SMOOTHING_UNSPECIFIED),
+        _matrix(m),
+        _bitmapInfo(bi),
+        _md(0),
+        _id(0)
+    {
+    }
+
+    /// Construct a static BitmapFill using a SWF tag.
+    BitmapFill(SWF::FillType t, movie_definition* md, boost::uint16_t id,
+            const SWFMatrix& m);
+
+    /// Copy a BitmapFill
+    //
+    /// The copied BitmapFill refers to the same bitmap id in the same
+    /// movie_definition as the original.
+    BitmapFill(const BitmapFill& other)
+        :
+        _type(other._type),
+        _smoothingPolicy(other._smoothingPolicy),
+        _matrix(other._matrix),
+        _bitmapInfo(other._bitmapInfo),
+        _md(other._md),
+        _id(other._id)
+    {}
+
+    /// Set this fill to a lerp of two other BitmapFills.
+    void setLerp(const BitmapFill& a, const BitmapFill& b, double ratio);
+
+    /// Get the Type of this BitmapFill
+    //
+    /// BitmapFills are either tiled or clipped.
+    Type type() const {
+        return _type;
+    }
+
+    /// Get the smoothing policy of this BitmapFill.
+    SmoothingPolicy smoothingPolicy() const {
+        return _smoothingPolicy;
+    }
+
+    /// Get the actual Bitmap data.
+    const BitmapInfo* bitmap() const;
+
+    /// Get the matrix of this BitmapFill.
+    const SWFMatrix& matrix() const {
+        return _matrix;
+    }
+
+private:
+
+    Type _type;
+
+    SmoothingPolicy _smoothingPolicy;
+
+    SWFMatrix _matrix;
+    
+    /// A Bitmap, used for dynamic fills and to cache parsed bitmaps.
+    mutable boost::intrusive_ptr<const BitmapInfo> _bitmapInfo;
+
+    /// The movie definition containing the bitmap
+    movie_definition* _md;
+
+    // The id of the tag containing the bitmap
+    boost::uint16_t _id;
+};
+
+
+/// A GradientFill
+//
+/// TODO: clean this up!
+class DSOEXPORT GradientFill
+{
+public:
+
+    /// The type of GradientFill
+    //
+    /// A Focal fill is a gradient fill with a focal point.
+    enum Type
+    {
+        LINEAR,
+        RADIAL
+    };
+
+    typedef std::vector<GradientRecord> GradientRecords;
+
+    /// Construct a GradientFill
+    //
+    /// Optionally the records can be passed here.
+    //
+    /// The actual matrix of the gradient depends on the type; the constructor
+    /// handles this, and users should just pass the user matrix.
+    GradientFill(Type t, const SWFMatrix& m,
+            const GradientRecords& = GradientRecords());
+
+    Type type() const {
+        return _type;
+    }
+
+    const SWFMatrix& matrix() const {
+        return _matrix;
+    }
+
+    /// Set this fill to a lerp of two other GradientFills.
+    void setLerp(const GradientFill& a, const GradientFill& b, double ratio);
+    
+    void setRecords(const GradientRecords& recs) {
+        assert(recs.size() > 1);
+        _gradients = recs;
+    }
+
+    /// Get the number of records in this GradientFill
+    size_t recordCount() const {
+        return _gradients.size();
+    }
+
+    /// Query the GradientRecord at the specified index
+    //
+    /// There are recordCount() records.
+    const GradientRecord& record(size_t i) const {
+        assert(i < _gradients.size());
+        return _gradients[i];
+    }
+
+    /// Set the focal point.
+    //
+    /// Value will be clamped to the range -1..1; callers don't need to check.
+    void setFocalPoint(double d);
+
+    /// Get the focal point of this GradientFill
+    //
+    /// If the focal point is 0.0, it is a simple radial fill.
+    double focalPoint() const {
+        return _focalPoint;
+    }
+
+    SWF::SpreadMode spreadMode;
+    SWF::InterpolationMode interpolation;
+
+private:
+
+    double _focalPoint;
+    GradientRecords _gradients;
+    Type _type;
+    SWFMatrix _matrix;
+};
+
+/// A SolidFill containing one color.
+//
+/// SolidFills are the simplest fill, containing only a single color.
+struct DSOEXPORT SolidFill
+{
+public:
+
+    /// Construct a SolidFill.
+    explicit SolidFill(const rgba& c)
+        :
+        _color(c)
+    {}
+
+    /// Copy a SolidFill.
+    SolidFill(const SolidFill& other)
+        :
+        _color(other._color)
+    {}
+
+    /// Set this fill to a lerp of two other SolidFills.
+    void setLerp(const SolidFill& a, const SolidFill& b, double ratio) {
+        _color.set_lerp(a.color(), b.color(), ratio);
+    }
+
+    /// Get the color of the fill.
+    rgba color() const {
+        return _color;
+    }
+
+private:
+    rgba _color;
+};
+
+/// FillStyle describes the various fill styles for shapes
+//
+/// The FillStyle class is effectively a boost::variant, but to allow passing
+/// FillStyles using a forward declaration (and reducing compile times),
+/// it's necessary to use a class.
+class DSOEXPORT FillStyle 
+{
+public:
+
+    typedef boost::variant<BitmapFill, SolidFill, GradientFill> Fill;
+    
+    /// Construct a FillStyle from any Fill.
+    //
+    /// The non-explicit templated contructor allows the same syntax as a
+    /// simple boost::variant:
+    ///     FillStyle f = GradientFill();
+    template<typename T> FillStyle(const T& f) : fill(f) {}
+
+    FillStyle(const FillStyle& other)
+        :
+        fill(other.fill)
+    {}
+
+    Fill fill;
+
+};
+ 
+/// Set the FillStyle to a lerp of a and b.
+//
+/// Callers must ensure that all FillStyles have exactly the same type! Most
+/// errors are caught by type-checking and will throw an unhandled exception.
+void setLerp(FillStyle& f, const FillStyle& a, const FillStyle& b, double t);
+
+/// Either a single or a morph-pair FillStyle.
+typedef std::pair<FillStyle, boost::optional<FillStyle> > OptionalFillPair;
+
+/// Read FillStyles from a stream
+//
+/// Read either single or morph-pair fill styles from a stream. 
+OptionalFillPair readFills(SWFStream& in, SWF::TagType t, movie_definition& m,
+        bool readMorph);
+
+DSOEXPORT std::ostream& operator<<(std::ostream& os,
+        const BitmapFill::SmoothingPolicy& p);
 
 } // namespace gnash
 
-
-#endif // GNASH_FILL_STYLE_H
+#endif 
 
 
 // Local Variables:

=== modified file 'libcore/FreetypeGlyphsProvider.cpp'
--- a/libcore/FreetypeGlyphsProvider.cpp        2010-07-28 07:57:23 +0000
+++ b/libcore/FreetypeGlyphsProvider.cpp        2010-07-31 16:42:49 +0000
@@ -27,7 +27,7 @@
 #include "GnashException.h"
 #include "ShapeRecord.h"
 #include "log.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 
 #ifdef USE_FREETYPE 
 # include <ft2build.h>
@@ -98,8 +98,8 @@
         _x(0),
         _y(0)
     {
-        fill_style f;
-        f.setSolid(rgba(255, 255, 255, 255));
+        /// A default fill style is solid white.
+        FillStyle f = SolidFill(rgba());
         _shape.addFillStyle(f);
         _shape.addPath(Path(_x, _y, 1, 0, 0, true));
         _currPath = &_shape.currentPath();

=== modified file 'libcore/Geometry.h'
--- a/libcore/Geometry.h        2010-03-12 23:37:40 +0000
+++ b/libcore/Geometry.h        2010-07-31 14:05:26 +0000
@@ -489,7 +489,7 @@
     ///    The fill index (1-based).
     ///    When this path is added to a DefineShapeTag,
     ///    the index (decremented by 1) will reference an element
-    ///    in the fill_style vector defined for that shape.
+    ///    in the FillStyle vector defined for that shape.
     ///    If zero, no fill will be active.
     ///
     void setLeftFill(unsigned f)
@@ -508,7 +508,7 @@
     ///    The fill index (1-based).
     ///    When this path is added to a DefineShapeTag,
     ///    the index (decremented by 1) will reference an element
-    ///    in the fill_style vector defined for that shape.
+    ///    in the FillStyle vector defined for that shape.
     ///    If zero, no fill will be active.
     ///
     void setRightFill(unsigned f)

=== modified file 'libcore/LineStyle.cpp'
--- a/libcore/LineStyle.cpp     2010-03-12 15:42:07 +0000
+++ b/libcore/LineStyle.cpp     2010-08-01 06:48:24 +0000
@@ -28,11 +28,29 @@
 #include "movie_definition.h"
 #include "SWF.h"
 #include "GnashException.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "GnashNumeric.h"
 
 namespace gnash {
 
+namespace {
+
+class GetColor : public boost::static_visitor<rgba>
+{
+public:
+    rgba operator()(const SolidFill& f) const {
+        return f.color();
+    }
+    rgba operator()(const GradientFill&) const {
+        return rgba();
+    }
+    rgba operator()(const BitmapFill&) const {
+        return rgba();
+    }
+};
+
+}
+
 LineStyle::LineStyle()
     :
     m_width(0),
@@ -50,18 +68,20 @@
 
 void
 LineStyle::read_morph(SWFStream& in, SWF::TagType t, movie_definition& md,
-    const RunResources& r, LineStyle *pOther)
+    const RunResources& /*r*/, LineStyle *pOther)
 {
     if (t == SWF::DEFINEMORPHSHAPE)
     {
         in.ensureBytes(2 + 2);
         m_width = in.read_u16();
         pOther->m_width = in.read_u16();
-        m_color.read(in, t);
-        pOther->m_color.read(in, t);
+        m_color = readRGBA(in);
+        pOther->m_color = readRGBA(in);
         return;
     }
 
+    assert(t == SWF::DEFINEMORPHSHAPE2 || t == SWF::DEFINEMORPHSHAPE2_);
+
     // MorphShape 2 from here down.
     in.ensureBytes(4 + 2);
 
@@ -84,66 +104,73 @@
         in.ensureBytes(2);
         _miterLimitFactor = in.read_short_ufixed();
     }
-    if (has_fill)
-    {
-        // read fill styles for strokes.
-        // TODO: don't throw away this information, should be passed to 
renderer.
-        fill_style f, g;
-        f.read(in, t, md, r, &g);
-        m_color = f.get_color();
-        pOther->m_color = g.get_color();
+    if (has_fill) {
+        OptionalFillPair fp = readFills(in, t, md, true);
+
+        // TODO: store a fill style properly, removing the need for the 
+        // visitor.
+        m_color = boost::apply_visitor(GetColor(), fp.first.fill);
+        pOther->m_color = boost::apply_visitor(GetColor(), fp.second->fill);
     }
-    else
-    {
-        m_color.read(in, t);
-        pOther->m_color.read(in, t);
+    else {
+        m_color = readRGBA(in);
+        pOther->m_color = readRGBA(in);
     }
 }
 
 void
 LineStyle::read(SWFStream& in, SWF::TagType t, movie_definition& md,
-        const RunResources& r)
+        const RunResources& /*r*/)
 {
-    if (!(t == SWF::DEFINESHAPE4 || t == SWF::DEFINESHAPE4_))
-    {
-        in.ensureBytes(2);
-        m_width = in.read_u16();
-        m_color.read(in, t);
-        return;
-    }
-
-    // TODO: Unfinished. Temporary to allow DefineShape4 to work in many
-    // cases, but does not work correctly in all cases.
-    in.ensureBytes(2+2);
-    m_width = in.read_u16();
-
-    int flags1 = in.read_u8();
-    int flags2 = in.read_u8();
-    _startCapStyle =  (CapStyle)((flags1 & 0xC0) >> 6);
-    _joinStyle     = (JoinStyle)((flags1 & 0x30) >> 4);
-    bool has_fill      =   flags1 & (1 << 3);
-    _scaleHorizontally = !(flags1 & (1 << 2));
-    _scaleVertically   = !(flags1 & (1 << 1));
-    _pixelHinting      =   flags1 & (1 << 0);
-    _noClose = flags2 & (1 << 2);
-    _endCapStyle = (CapStyle) (flags2 & 0x03); 
-
-    if (_joinStyle == JOIN_MITER) 
-    {
-        in.ensureBytes(2);
-        _miterLimitFactor = in.read_short_ufixed();
-    }
-    if (has_fill)
-    {
-        // read fill styles for strokes.
-        // TODO: don't throw away this information, should be passed to 
renderer.
-        fill_style f;
-        f.read(in, t, md, r);
-        m_color = f.get_color();
-    }
-    else
-    {
-        m_color.read(in, t);
+    switch (t) {
+
+        default:
+            in.ensureBytes(2);
+            m_width = in.read_u16();
+            m_color = readRGBA(in);
+            return;
+
+        case SWF::DEFINESHAPE:
+        case SWF::DEFINESHAPE2:
+            in.ensureBytes(2);
+            m_width = in.read_u16();
+            m_color = readRGB(in);
+            return;
+
+        case SWF::DEFINESHAPE4:
+        case SWF::DEFINESHAPE4_:
+        {
+            // TODO: Unfinished. Temporary to allow DefineShape4 to work in
+            // many cases, but does not work correctly in all cases.
+            in.ensureBytes(2+2);
+            m_width = in.read_u16();
+
+            const boost::uint8_t flags1 = in.read_u8();
+            const boost::uint8_t flags2 = in.read_u8();
+
+            _startCapStyle = (CapStyle)((flags1 & 0xC0) >> 6);
+            _joinStyle = (JoinStyle)((flags1 & 0x30) >> 4);
+            const bool has_fill  =   flags1 & (1 << 3);
+            _scaleHorizontally = !(flags1 & (1 << 2));
+            _scaleVertically   = !(flags1 & (1 << 1));
+            _pixelHinting      =   flags1 & (1 << 0);
+            _noClose = flags2 & (1 << 2);
+            _endCapStyle = (CapStyle) (flags2 & 0x03); 
+
+            if (_joinStyle == JOIN_MITER) {
+                in.ensureBytes(2);
+                _miterLimitFactor = in.read_short_ufixed();
+            }
+            if (has_fill) {
+                // TODO: store a fill style properly, removing the need for 
the 
+                // visitor.
+                OptionalFillPair fp = readFills(in, t, md, false);
+                m_color = boost::apply_visitor(GetColor(), fp.first.fill);
+            }
+            else {
+                m_color = readRGBA(in);
+            }
+        }
     }
 }
 
@@ -151,7 +178,7 @@
 LineStyle::set_lerp(const LineStyle& ls1, const LineStyle& ls2, float ratio)
 {
     m_width = static_cast<boost::uint16_t>(
-        frnd(flerp(ls1.getThickness(), ls2.getThickness(), ratio)));
+        frnd(lerp<float>(ls1.getThickness(), ls2.getThickness(), ratio)));
     m_color.set_lerp(ls1.get_color(), ls2.get_color(), ratio);
     if ( ls1._scaleVertically != ls2._scaleVertically )
     {
@@ -163,8 +190,7 @@
     }
 }
 
-// end of namespace
-}
+} // namespace gnash
 
 
 // Local Variables:

=== modified file 'libcore/LineStyle.h'
--- a/libcore/LineStyle.h       2010-01-18 06:21:14 +0000
+++ b/libcore/LineStyle.h       2010-07-30 15:03:01 +0000
@@ -186,6 +186,12 @@
 
     float _miterLimitFactor;
 };
+    
+inline void
+setLerp(LineStyle& s, const LineStyle& ls1, const LineStyle& ls2, double 
ratio) 
+{
+    s.set_lerp(ls1, ls2, ratio);
+}
 
 } // namespace gnash
 

=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am       2010-07-24 13:44:22 +0000
+++ b/libcore/Makefile.am       2010-07-31 14:05:26 +0000
@@ -124,7 +124,7 @@
        StreamProvider.cpp \
        Button.cpp \
        DisplayList.cpp \
-       fill_style.cpp \
+       FillStyle.cpp \
        Font.cpp \
        fontlib.cpp \
        impl.cpp \
@@ -277,7 +277,7 @@
        swf/TagLoadersTable.h \
        swf/SWF.h \
        MovieFactory.h \
-       fill_style.h \
+       FillStyle.h \
        LineStyle.h \
        BitmapInfo.h \
        RGBA.h  \

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2010-07-13 06:16:31 +0000
+++ b/libcore/MovieClip.h       2010-07-31 14:05:26 +0000
@@ -47,7 +47,7 @@
     class swf_event;
     class drag_state;
     class LoadVariablesThread;
-    class gradient_record;
+    class GradientRecord;
     class TextField;
     class BitmapData_as;
     class BitmapInfo;
@@ -559,73 +559,10 @@
             const SWFRect& clipRect = SWFRect(),
             bool smooth = false);
 
-    /// @name Drawing API
-    /// @{ 
-    
-    void lineStyle(boost::uint16_t thickness, const rgba& color,
-        bool vScale=true, bool hScale=true,
-        bool pixelHinting=false,
-        bool noClose=false,
-        CapStyle startCapStyle=CAP_ROUND,
-        CapStyle endCapStyle=CAP_ROUND,
-        JoinStyle joinStyle=JOIN_ROUND,
-        float miterLimitFactor=1.0f)
-    {
-        _drawable.lineStyle(thickness, color, vScale, hScale,
-            pixelHinting, noClose,
-            startCapStyle, endCapStyle, joinStyle,
-            miterLimitFactor);
-    }
-
-    void resetLineStyle()
-    {
-        _drawable.resetLineStyle();
-    }
-
-    void beginFill(const rgba& color)
-    {
-        _drawable.beginFill(color);
-    }
-
-    void beginLinearGradientFill(const std::vector<gradient_record>& grad,
-            const SWFMatrix& mat)
-    {
-        _drawable.beginLinearGradientFill(grad, mat);
-    }
-
-    void beginRadialGradientFill(const std::vector<gradient_record>& grad,
-            const SWFMatrix& mat)
-    {
-        _drawable.beginRadialGradientFill(grad, mat);
-    }
-
-    void endFill()
-    {
-        _drawable.endFill();
-    }
-
-    void moveTo(boost::int32_t x, boost::int32_t y)
-    {
-        _drawable.moveTo(x, y);
-    }
-
-    void lineTo(boost::int32_t x, boost::int32_t y)
-    {
-        set_invalidated();
-        _drawable.lineTo(x, y, getDefinitionVersion());
-    }
-
-    void curveTo(boost::int32_t cx, boost::int32_t cy, 
-                 boost::int32_t ax, boost::int32_t ay)
-    {
-        set_invalidated();
-        _drawable.curveTo(cx, cy, ax, ay, getDefinitionVersion());
-    }
-
-    void clear()
-    {
-        set_invalidated();
-        _drawable.clear();
+    /// Direct access to the Graphics object for drawing.
+    DynamicShape& graphics() {
+        set_invalidated();
+        return _drawable;
     }
 
     /// Set focus to this MovieClip

=== modified file 'libcore/RGBA.cpp'
--- a/libcore/RGBA.cpp  2010-01-18 06:38:43 +0000
+++ b/libcore/RGBA.cpp  2010-08-01 06:51:26 +0000
@@ -26,59 +26,44 @@
 
 namespace gnash {
 
-void
-rgba::read(SWFStream& in, SWF::TagType tag)
-{
-    switch (tag)
-    {
-        case SWF::DEFINESHAPE:
-        case SWF::DEFINESHAPE2:
-            read_rgb(in);
-            break;
-        default:
-        case SWF::DEFINESHAPE3:
-            read_rgba(in);
-            break;
-    }
-}
-
-void
-rgba::read_rgba(SWFStream& in)
-{
-    read_rgb(in);
-    in.ensureBytes(1);
-    m_a = in.read_u8();
-}
-
-/// Can throw ParserException on premature end of input stream
-void
-rgba::read_rgb(SWFStream& in)
-{
-    in.ensureBytes(3);
-    m_r = in.read_u8();
-    m_g = in.read_u8();
-    m_b = in.read_u8();
-    m_a = 0x0FF;
-}
-
 std::string
 rgba::toShortString() const
 {
     std::stringstream ss;
-    ss << (unsigned)m_r << ","
-        << (unsigned)m_g << ","
-        << (unsigned)m_b << ","
-        << (unsigned)m_a;
+    ss << +m_r << "," << +m_g << "," << +m_b << "," << +m_a;
     return ss.str();
 }
 
 void
 rgba::set_lerp(const rgba& a, const rgba& b, float f)
 {
-    m_r = static_cast<boost::uint8_t>(frnd(flerp(a.m_r, b.m_r, f)));
-    m_g = static_cast<boost::uint8_t>(frnd(flerp(a.m_g, b.m_g, f)));
-    m_b = static_cast<boost::uint8_t>(frnd(flerp(a.m_b, b.m_b, f)));
-    m_a = static_cast<boost::uint8_t>(frnd(flerp(a.m_a, b.m_a, f)));
+    m_r = frnd(lerp<float>(a.m_r, b.m_r, f));
+    m_g = frnd(lerp<float>(a.m_g, b.m_g, f));
+    m_b = frnd(lerp<float>(a.m_b, b.m_b, f));
+    m_a = frnd(lerp<float>(a.m_a, b.m_a, f));
+}
+
+rgba
+readRGBA(SWFStream& in)
+{
+    in.ensureBytes(4);
+    const boost::uint8_t r = in.read_u8();
+    const boost::uint8_t g = in.read_u8();
+    const boost::uint8_t b = in.read_u8();
+    const boost::uint8_t a = in.read_u8();
+    return rgba(r, g, b, a);
+}
+
+/// Can throw ParserException on premature end of input stream
+rgba
+readRGB(SWFStream& in)
+{
+    in.ensureBytes(3);
+    const boost::uint8_t r = in.read_u8();
+    const boost::uint8_t g = in.read_u8();
+    const boost::uint8_t b = in.read_u8();
+    const boost::uint8_t a = 0xff;
+    return rgba(r, g, b, a);
 }
 
 rgba
@@ -101,11 +86,8 @@
 std::ostream&
 operator<<(std::ostream& os, const rgba& r)
 {
-    return os << "rgba: "
-        << static_cast<unsigned>(r.m_r) << ","
-        << static_cast<unsigned>(r.m_g) << ","
-        << static_cast<unsigned>(r.m_b) << ","
-        << static_cast<unsigned>(r.m_a);
+    return os << "rgba: " << +r.m_r << "," << +r.m_g << "," << +r.m_b << ","
+        << +r.m_a;
 }
 
 } // namespace gnash

=== modified file 'libcore/RGBA.h'
--- a/libcore/RGBA.h    2010-01-18 06:38:37 +0000
+++ b/libcore/RGBA.h    2010-08-01 06:48:24 +0000
@@ -101,17 +101,6 @@
         return toRGB() + (m_a << 24);
     }
 
-    /// Initialize from input stream.
-    //
-    /// @param in   The input SWFStream
-    ///
-    /// @param t    The tag type, used to determine whether to read an RGB
-    ///             or RGBA record.
-    //
-    /// Throw a ParserException if there are not enough bytes in the
-    /// currently opened tag for reading. See SWFStream::ensureBytes()
-    void read(SWFStream& in, SWF::TagType t);
-
     /// Set r, g, b, a values
     void set(boost::uint8_t r, boost::uint8_t g, boost::uint8_t b,
             boost::uint8_t a) {
@@ -127,15 +116,6 @@
     /// Neater string output (example: "0,0,0,255")
     std::string toShortString() const;
 
-    /// Initialize from input stream (reads RGBA)
-    //
-    /// Throw a ParserException if there's no enough bytes in the
-    /// currently opened tag for reading. See SWFStream::ensureBytes()
-    void read_rgba(SWFStream& in);
-
-    /// Initialize from intput stream (reads RGB)
-    void read_rgb(SWFStream& in);
-
     friend std::ostream& operator<< (std::ostream& os, const rgba& r);
 
     bool operator==(const rgba& o) const {
@@ -154,6 +134,15 @@
 };
 
 std::ostream& operator<< (std::ostream& os, const rgba& r);
+
+/// Initialize from input stream (reads RGBA)
+//
+/// Throw a ParserException if there's no enough bytes in the
+/// currently opened tag for reading. See SWFStream::ensureBytes()
+rgba readRGBA(SWFStream& in);
+
+/// Initialize from intput stream (reads RGB)
+rgba readRGB(SWFStream& in);
     
 /// Create an RGBA value from a hex string (e.g. FF0000)
 //

=== modified file 'libcore/SWFMatrix.cpp'
--- a/libcore/SWFMatrix.cpp     2010-03-12 23:37:40 +0000
+++ b/libcore/SWFMatrix.cpp     2010-08-01 07:47:27 +0000
@@ -51,37 +51,29 @@
 
 } // anonymous namepace
 
-SWFMatrix::SWFMatrix()
-{
-    // Default to identity.
-    sx = sy = 65536;
-    shx = shy = tx = ty = 0;
-}
-
-void
-SWFMatrix::read(SWFStream& in)
-// Initialize from the stream.
+SWFMatrix
+readSWFMatrix(SWFStream& in)
 {
     in.align();
 
-    set_identity();
-
     in.ensureBits(1);
-    bool    has_scale = in.read_bit(); 
-    if (has_scale)
-    {
+    const bool has_scale = in.read_bit(); 
+
+    boost::int32_t sx = 65536;
+    boost::int32_t sy = 65536;
+    if (has_scale) {
         in.ensureBits(5);
-        int scale_nbits = in.read_uint(5);
-
+        const boost::uint8_t scale_nbits = in.read_uint(5);
         in.ensureBits(scale_nbits * 2);
         sx = in.read_sint(scale_nbits);
         sy = in.read_sint(scale_nbits);
     }
 
     in.ensureBits(1);
-    bool  has_rotate = in.read_bit();
-    if (has_rotate)
-    {
+    const bool has_rotate = in.read_bit();
+    boost::int32_t shx = 0;
+    boost::int32_t shy = 0;
+    if (has_rotate) {
         in.ensureBits(5);
         int rotate_nbits = in.read_uint(5);
 
@@ -91,21 +83,15 @@
     }
 
     in.ensureBits(5);
-    int translate_nbits = in.read_uint(5);
-    if (translate_nbits > 0)
-    {
+    const boost::uint8_t translate_nbits = in.read_uint(5);
+    boost::int32_t tx = 0;
+    boost::int32_t ty = 0;
+    if (translate_nbits) {
         in.ensureBits(translate_nbits * 2);
         tx = in.read_sint(translate_nbits);
         ty = in.read_sint(translate_nbits);
     }
-}
-
-bool
-SWFMatrix::is_valid() const
-{
-    // The integer SWFMatrix is always valid now from outside.
-    // swallow it if anything wrong inside this class.
-    return true;
+    return SWFMatrix(sx, shx, shy, sy, tx, ty);
 }
 
 void
@@ -120,8 +106,8 @@
 void
 SWFMatrix::transform(boost::int32_t& x, boost::int32_t& y) const
 {
-    boost::int32_t  t0 = Fixed16Mul(sx, x) + Fixed16Mul(shy, y) + tx;
-    boost::int32_t  t1 = Fixed16Mul(shx,x) + Fixed16Mul(sy,  y) + ty;
+    const boost::int32_t t0 = Fixed16Mul(sx, x) + Fixed16Mul(shy, y) + tx;
+    const boost::int32_t t1 = Fixed16Mul(shx,x) + Fixed16Mul(sy,  y) + ty;
     x = t0;
     y = t1;
 }
@@ -129,10 +115,10 @@
 void
 SWFMatrix::transform(geometry::Range2d<boost::int32_t>& r) const
 {
-    boost::int32_t xmin = r.getMinX(),
-                   xmax = r.getMaxX(),
-                   ymin = r.getMinY(),
-                   ymax = r.getMaxY();
+    const boost::int32_t xmin = r.getMinX();
+    const boost::int32_t xmax = r.getMaxX();
+    const boost::int32_t ymin = r.getMinY();
+    const boost::int32_t ymax = r.getMaxY();
 
     point p0(xmin, ymin);
     point p1(xmin, ymax);
@@ -152,7 +138,6 @@
 
 void
 SWFMatrix::set_identity()
-// Set the SWFMatrix to identity.
 {
     sx = sy = 65536;
     shx = shy = tx = ty = 0;
@@ -160,11 +145,8 @@
 
 void
 SWFMatrix::concatenate(const SWFMatrix& m)
-// Concatenate m's transform onto ours.  When
-// transforming points, m happens first, then our
-// original SWFMatrix.
 {
-    SWFMatrix  t;
+    SWFMatrix t;
     t.sx =  Fixed16Mul(sx, m.sx)  + Fixed16Mul(shy, m.shx);
     t.shx = Fixed16Mul(shx, m.sx) + Fixed16Mul(sy, m.shx);
     t.shy = Fixed16Mul(sx, m.shy) + Fixed16Mul(shy, m.sy);
@@ -196,16 +178,16 @@
     sy  = Fixed16Mul(sy, DoubleToFixed16(yscale)); 
 }
 
+// Set this SWFMatrix to a blend of m1 and m2, parameterized by t.
 void
 SWFMatrix::set_lerp(const SWFMatrix& m1, const SWFMatrix& m2, float t)
-// Set this SWFMatrix to a blend of m1 and m2, parameterized by t.
 {
-    sx = flerp(m1.sx, m2.sx, t);
-    shx = flerp(m1.shx, m2.shx, t);
-    shy = flerp(m1.shy, m2.shy, t);
-    sy = flerp(m1.sy, m2.sy, t);
-    tx = flerp(m1.tx, m2.tx, t);
-    ty = flerp(m1.ty, m2.ty, t);
+    sx = lerp<float>(m1.sx, m2.sx, t);
+    shx = lerp<float>(m1.shx, m2.shx, t);
+    shy = lerp<float>(m1.shy, m2.shy, t);
+    sy = lerp<float>(m1.sy, m2.sy, t);
+    tx = lerp<float>(m1.tx, m2.tx, t);
+    ty = lerp<float>(m1.ty, m2.ty, t);
 }
 
 void
@@ -213,8 +195,8 @@
 // Set the scale & rotation part of the SWFMatrix.
 // angle in radians.
 {
-    double   cos_angle = std::cos(angle);
-    double   sin_angle = std::sin(angle);
+    const double cos_angle = std::cos(angle);
+    const double sin_angle = std::sin(angle);
     sx  = DoubleToFixed16(x_scale * cos_angle);
     shy = DoubleToFixed16(y_scale * -sin_angle);
     shx = DoubleToFixed16(x_scale * sin_angle);
@@ -224,40 +206,43 @@
 void
 SWFMatrix::set_x_scale(double xscale)
 {
-    double rot_x = std::atan2(static_cast<double>(shx), 
static_cast<double>(sx));
-    sx  =  DoubleToFixed16(xscale * std::cos(rot_x));
-    shx =  DoubleToFixed16(xscale * std::sin(rot_x)); 
+    const double rot_x =
+        std::atan2(static_cast<double>(shx), static_cast<double>(sx));
+    sx = DoubleToFixed16(xscale * std::cos(rot_x));
+    shx = DoubleToFixed16(xscale * std::sin(rot_x)); 
 }
 
 void
 SWFMatrix::set_y_scale(double yscale)
 {
-    double rot_y = std::atan2(static_cast<double>(-shy), 
static_cast<double>(sy));
+    const double rot_y =
+        std::atan2(static_cast<double>(-shy), static_cast<double>(sy));
 
     shy = -DoubleToFixed16(yscale * std::sin(rot_y));
-    sy  =  DoubleToFixed16(yscale * std::cos(rot_y));
+    sy = DoubleToFixed16(yscale * std::cos(rot_y));
 }
 
 void
 SWFMatrix::set_scale(double xscale, double yscale)
 {
-    double rotation = get_rotation();
+    const double rotation = get_rotation();
     set_scale_rotation(xscale, yscale, rotation); 
 }
 
 void
 SWFMatrix::set_rotation(double rotation)
 {   
-    double rot_x = std::atan2(static_cast<double>(shx), 
static_cast<double>(sx));
-    double rot_y = std::atan2(static_cast<double>(-shy),
-    static_cast<double>(sy));
-    double scale_x = get_x_scale();
-    double scale_y = get_y_scale();
+    const double rot_x =
+        std::atan2(static_cast<double>(shx), static_cast<double>(sx));
+    const double rot_y =
+        std::atan2(static_cast<double>(-shy), static_cast<double>(sy));
+    const double scale_x = get_x_scale();
+    const double scale_y = get_y_scale();
  
-    sx  = DoubleToFixed16(scale_x * std::cos(rotation));
+    sx = DoubleToFixed16(scale_x * std::cos(rotation));
     shx = DoubleToFixed16(scale_x * std::sin(rotation)); 
     shy = -DoubleToFixed16(scale_y * std::sin(rot_y - rot_x + rotation));
-    sy  =  DoubleToFixed16(scale_y * std::cos(rot_y - rot_x + rotation));
+    sy = DoubleToFixed16(scale_y * std::cos(rot_y - rot_x + rotation));
 }
 
 void
@@ -273,12 +258,12 @@
 void 
 SWFMatrix::transform(SWFRect& r) const
 {
-    if ( r.is_null() ) return;
+    if (r.is_null()) return;
 
-    boost::int32_t x1 = r.get_x_min();
-    boost::int32_t y1 = r.get_y_min();
-    boost::int32_t x2 = r.get_x_max();
-    boost::int32_t y2 = r.get_y_max();
+    const boost::int32_t x1 = r.get_x_min();
+    const boost::int32_t y1 = r.get_y_min();
+    const boost::int32_t x2 = r.get_x_max();
+    const boost::int32_t y2 = r.get_y_max();
 
     point p0(x1, y1);
     point p1(x2, y1);
@@ -300,29 +285,24 @@
 SWFMatrix&
 SWFMatrix::invert()
 {
-    boost::int64_t det = determinant();
-    if(det == 0)
-    {
-        //log_debug("Matrix not invertible, setting to identity on invert 
request");
-        // tested in misc-ming.all/SWFMatrix_test.c (seek "SWFMatrix 
inversion")
+    const boost::int64_t det = determinant();
+    if (det == 0) {
         set_identity();
-    }
-    else
-    {
-        double  d = 65536.0 * 65536.0 / det;
-        boost::int32_t t0, t4;
-        
-        t0  = (boost::int32_t)(sy * d);
-        sy  = (boost::int32_t)(sx * d);
-        shy = (boost::int32_t)(-shy * d);
-        shx = (boost::int32_t)(-shx * d);
-
-        t4 = - ( Fixed16Mul(tx, t0) + Fixed16Mul(ty, shy) );
-        ty = - ( Fixed16Mul(tx, shx)+ Fixed16Mul(ty, sy) );
-
-        sx = t0;
-        tx = t4;
-    }
+        return *this;
+    }
+
+    const double d = 65536.0 * 65536.0 / det;
+    
+    const boost::int32_t t0 = (boost::int32_t)(sy * d);
+    sy  = (boost::int32_t)(sx * d);
+    shy = (boost::int32_t)(-shy * d);
+    shx = (boost::int32_t)(-shx * d);
+
+    const boost::int32_t t4 = - (Fixed16Mul(tx, t0) + Fixed16Mul(ty, shy));
+    ty = - (Fixed16Mul(tx, shx) + Fixed16Mul(ty, sy));
+
+    sx = t0;
+    tx = t4;
 
     return *this;
 }

=== modified file 'libcore/SWFMatrix.h'
--- a/libcore/SWFMatrix.h       2010-03-12 23:37:40 +0000
+++ b/libcore/SWFMatrix.h       2010-08-01 07:47:27 +0000
@@ -61,29 +61,45 @@
     /// Xshear, 16.16 fixed point. yx in swfdec. 'b' in AS Matrix.
     int shx;
 
+    /// Yshear, 16.16 fixed point. xy in swfdec. 'c' in AS Matrix.
+    int shy;
+
+    /// Yscale, 16.16 fixed point. yy in swfdec. 'd' in AS Matrix.
+    int sy; 
+
     /// Xtranslation, TWIPS. x0 in swfdec. 'tx' in AS Matrix.
     int tx; 
 
-    /// Yscale, 16.16 fixed point. yy in swfdec. 'd' in AS Matrix.
-    int sy; 
-
-    /// Yshear, 16.16 fixed point. xy in swfdec. 'c' in AS Matrix.
-    int shy;
-
     /// Ytranslation, TWIPS. y0 in swfdec. 'ty' in AS Matrix.
     int ty; 
              
     friend bool operator== (const SWFMatrix&, const SWFMatrix&);
     friend std::ostream& operator<< (std::ostream&, const SWFMatrix&);
     
-    /// Defaults to identity
-    SWFMatrix();
+    /// Construct an identity SWFMatrix
+    SWFMatrix()
+        :
+        sx(65536),
+        shx(0),
+        shy(0),
+        sy(65536),
+        tx(0),
+        ty(0)
+    {}
 
-    /// Check validity of the SWFMatrix values
-    bool    is_valid() const;
+    /// Construct a SWFMatrix with all values.
+    SWFMatrix(int a, int b, int c, int d, int x, int y)
+        :
+        sx(a),
+        shx(b),
+        shy(c),
+        sy(d),
+        tx(x),
+        ty(y)
+    {}
 
     /// Set the SWFMatrix to identity.
-    void    set_identity();
+    void set_identity();
 
     /// Concatenate m's transform onto ours. 
     //
@@ -143,9 +159,6 @@
         ty = y;
     }
 
-    /// Initialize from the SWF input stream.
-    void    read(SWFStream& in);
-
     /// Transform a given point by our SWFMatrix
     void transform(geometry::Point2d& p) const;
 
@@ -197,6 +210,9 @@
 
 }; //end of SWFMatrix
 
+/// Read from input stream.
+SWFMatrix readSWFMatrix(SWFStream& in);
+
 inline bool operator== (const SWFMatrix& a, const SWFMatrix& b)
 {
     return  

=== modified file 'libcore/SWFRect.cpp'
--- a/libcore/SWFRect.cpp       2010-07-19 08:08:00 +0000
+++ b/libcore/SWFRect.cpp       2010-07-31 16:10:47 +0000
@@ -134,16 +134,17 @@
     expand_to(p3.x, p3.y);
 }
 
-void    SWFRect::set_lerp(const SWFRect& a, const SWFRect& b, float t)
+void
+SWFRect::set_lerp(const SWFRect& a, const SWFRect& b, float t)
 // Set this to the lerp of a and b.
 {
     assert( !a.is_null() );
     assert( !b.is_null() );
     
-    _xMin = (boost::int32_t)(flerp(a.get_x_min(), b.get_x_min(), t));
-    _yMin = (boost::int32_t)(flerp(a.get_y_min(), b.get_y_min(), t));
-    _xMax = (boost::int32_t)(flerp(a.get_x_max(), b.get_x_max(), t));
-    _yMax = (boost::int32_t)(flerp(a.get_y_max(), b.get_y_max(), t));
+    _xMin = lerp<float>(a.get_x_min(), b.get_x_min(), t);
+    _yMin = lerp<float>(a.get_y_min(), b.get_y_min(), t);
+    _xMax = lerp<float>(a.get_x_max(), b.get_x_max(), t);
+    _yMax = lerp<float>(a.get_y_max(), b.get_y_max(), t);
 }
 
 void

=== modified file 'libcore/asobj/MovieClip_as.cpp'
--- a/libcore/asobj/MovieClip_as.cpp    2010-07-28 07:57:23 +0000
+++ b/libcore/asobj/MovieClip_as.cpp    2010-07-31 16:42:49 +0000
@@ -36,7 +36,7 @@
 #include "NativeFunction.h" 
 #include "Bitmap.h"
 #include "Array_as.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "namedStrings.h"
 
 namespace gnash {
@@ -1430,19 +1430,7 @@
 movieclip_endFill(const fn_call& fn)
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.endFill(%s): args will be discarded"),
-            ss.str());
-    }
-    );
-#ifdef DEBUG_DRAWING_API
-    log_debug("%s.endFill();", movieclip->getTarget());
-#endif
-    movieclip->endFill();
+    movieclip->graphics().endFill();
     return as_value();
 }
 
@@ -1451,52 +1439,24 @@
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
 
-    if ( fn.nargs < 2 )
-    {
+    if (fn.nargs < 2) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_aserror(_("MovieClip.lineTo() needs at least two arguments"));
         );
         return as_value();
     }
 
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 2 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.lineTo(%s): args after the first two "
-                        "will be discarded"), ss.str());
-    }
-    );
-
     double x = fn.arg(0).to_number();
     double y = fn.arg(1).to_number();
         
-    if (!isFinite(x) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.lineTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        x = 0;
-    }
-     
-    if (!isFinite(y) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.lineTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        y = 0;
-    }
+    if (!isFinite(x)) x = 0;
+    if (!isFinite(y)) y = 0;
 
 #ifdef DEBUG_DRAWING_API
     log_debug("%s.lineTo(%g,%g);", movieclip->getTarget(), x, y);
 #endif
-    movieclip->lineTo(pixelsToTwips(x), pixelsToTwips(y));
+    movieclip->graphics().lineTo(pixelsToTwips(x), pixelsToTwips(y),
+            movieclip->getDefinitionVersion());
     return as_value();
 }
 
@@ -1505,52 +1465,20 @@
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
 
-    if ( fn.nargs < 2 )
-    {
+    if (fn.nargs < 2) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_aserror(_("MovieClip.moveTo() takes two args"));
         );
         return as_value();
     }
 
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 2 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.moveTo(%s): args after the first two will "
-                        "be discarded"), ss.str());
-    }
-    );
-
     double x = fn.arg(0).to_number();
     double y = fn.arg(1).to_number();
      
-    if (!isFinite(x) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.moveTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        x = 0;
-    }
-     
-    if (!isFinite(y) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.moveTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        y = 0;
-    }
+    if (!isFinite(x)) x = 0;
+    if (!isFinite(y)) y = 0;
 
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.moveTo(%g,%g);"), movieclip->getTarget(), x, y);
-#endif
-    movieclip->moveTo(pixelsToTwips(x), pixelsToTwips(y));
+    movieclip->graphics().moveTo(pixelsToTwips(x), pixelsToTwips(y));
     return as_value();
 }
 
@@ -1565,9 +1493,8 @@
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
 
-    if ( ! fn.nargs )
-    {
-        movieclip->resetLineStyle();
+    if (!fn.nargs) {
+        movieclip->graphics().resetLineStyle();
         return as_value();
     }
 
@@ -1587,8 +1514,7 @@
     int arguments = fn.nargs;
 
     const int swfVersion = getSWFVersion(fn);
-    if (swfVersion < 8 && fn.nargs > 3)
-    {
+    if (swfVersion < 8 && fn.nargs > 3) {
         IF_VERBOSE_ASCODING_ERRORS(
             std::ostringstream ss;
             fn.dump_args(ss);
@@ -1598,15 +1524,8 @@
         arguments = 3;
     }
 
-    switch (arguments)
-    {
+    switch (arguments) {
         default:
-            IF_VERBOSE_ASCODING_ERRORS(
-                std::ostringstream ss;
-                fn.dump_args(ss);
-                log_aserror(_("MovieClip.lineStyle(%s): args after the "
-                              "first eight will be discarded"), ss.str());
-                );
         case 8:
             miterLimitFactor = clamp<int>(toInt(fn.arg(7)), 1, 255);
         case 7:
@@ -1615,8 +1534,7 @@
             if (joinStyleStr == "miter") joinStyle = JOIN_MITER;
             else if (joinStyleStr == "round") joinStyle = JOIN_ROUND;
             else if (joinStyleStr == "bevel") joinStyle = JOIN_BEVEL;
-            else
-            {
+            else {
                 IF_VERBOSE_ASCODING_ERRORS(
                     std::ostringstream ss;
                     fn.dump_args(ss);
@@ -1632,8 +1550,7 @@
             if (capStyleStr == "none") capStyle = CAP_NONE;
             else if (capStyleStr == "round") capStyle = CAP_ROUND;
             else if (capStyleStr == "square") capStyle = CAP_SQUARE;
-            else
-            {
+            else {
                 IF_VERBOSE_ASCODING_ERRORS(
                     std::ostringstream ss;
                     fn.dump_args(ss);
@@ -1648,21 +1565,17 @@
             // Both values to be set here are true, so just set the
             // appropriate values to false.
             const std::string noScaleString = fn.arg(4).to_string();
-            if (noScaleString == "none")
-            {
-                scaleThicknessVertically = false;
-                scaleThicknessHorizontally = false;
-            }
-            else if (noScaleString == "vertical")
-            {
-                scaleThicknessVertically = false;
-            }
-            else if (noScaleString == "horizontal")
-            {
-                scaleThicknessHorizontally = false;
-            }
-            else if (noScaleString != "normal")
-            {
+            if (noScaleString == "none") {
+                scaleThicknessVertically = false;
+                scaleThicknessHorizontally = false;
+            }
+            else if (noScaleString == "vertical") {
+                scaleThicknessVertically = false;
+            }
+            else if (noScaleString == "horizontal") {
+                scaleThicknessHorizontally = false;
+            }
+            else if (noScaleString != "normal") {
                 IF_VERBOSE_ASCODING_ERRORS(
                     std::ostringstream ss;
                     fn.dump_args(ss);
@@ -1700,12 +1613,9 @@
 
     rgba color(r, g, b, a);
 
-#ifdef DEBUG_DRAWING_API
-    log_debug("%s.lineStyle(%d,%d,%d,%d);", movieclip->getTarget(), thickness, 
r, g, b);
-#endif
-    movieclip->lineStyle(thickness, color,
-    scaleThicknessVertically, scaleThicknessHorizontally,
-    pixelHinting, noClose, capStyle, capStyle, joinStyle, miterLimitFactor);
+    movieclip->graphics().lineStyle(thickness, color,
+        scaleThicknessVertically, scaleThicknessHorizontally,
+        pixelHinting, noClose, capStyle, capStyle, joinStyle, 
miterLimitFactor);
 
     return as_value();
 }
@@ -1715,78 +1625,30 @@
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
 
-    if ( fn.nargs < 4 )
-    {
+    if (fn.nargs < 4) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_aserror(_("MovieClip.curveTo() takes four args"));
         );
         return as_value();
     }
 
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 4 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.curveTo(%s): args after the first four "
-                "will be discarded"), ss.str());
-    }
-    );
-
     double cx = fn.arg(0).to_number();
     double cy = fn.arg(1).to_number();
     double ax = fn.arg(2).to_number();
     double ay = fn.arg(3).to_number();
 
-    if (!isFinite(cx))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        cx = 0;
-    }
-     
-    if (!isFinite(cy))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        cy = 0;
-    }
-
-    if (!isFinite(ax))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite third argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        ax = 0;
-    }
-     
-    if (!isFinite(ay))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite fourth argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        ay = 0;
-    }
+    if (!isFinite(cx)) cx = 0;
+    if (!isFinite(cy)) cy = 0;
+    if (!isFinite(ax)) ax = 0;
+    if (!isFinite(ay)) ay = 0;
 
 #ifdef DEBUG_DRAWING_API
     log_debug(_("%s.curveTo(%g,%g,%g,%g);"), movieclip->getTarget(),
             cx, cy, ax, ay);
 #endif
-    movieclip->curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
-            pixelsToTwips(ax), pixelsToTwips(ay));
+    movieclip->graphics().curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
+            pixelsToTwips(ax), pixelsToTwips(ay),
+            movieclip->getDefinitionVersion());
 
     return as_value();
 }
@@ -1795,21 +1657,7 @@
 movieclip_clear(const fn_call& fn)
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.clear(%s): args will be discarded"),
-            ss.str());
-    }
-    );
-
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.clear();"), movieclip->getTarget());
-#endif
-    movieclip->clear();
-
+    movieclip->graphics().clear();
     return as_value();
 }
 
@@ -1818,46 +1666,30 @@
 {
     MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
 
-    if ( fn.nargs < 1 )
-    {
+    if (fn.nargs < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("beginFill() with no args is a no-op");
+            log_aserror("beginFill() with no args is a no-op");
         );
         return as_value();
     }
 
-    boost::uint8_t r = 0;
-    boost::uint8_t g = 0;
-    boost::uint8_t b = 0;
-    boost::uint8_t a = 255;
-
-
     // 2^24 is the max here
-    boost::uint32_t rgbval = boost::uint32_t(
-            clamp<float>(fn.arg(0).to_number(), 0, 16777216));
-    r = boost::uint8_t( (rgbval&0xFF0000) >> 16);
-    g = boost::uint8_t( (rgbval&0x00FF00) >> 8);
-    b = boost::uint8_t( (rgbval&0x0000FF) );
-
-    if ( fn.nargs > 1 )
-    {
+    const boost::uint32_t rgbval =
+        clamp<float>(fn.arg(0).to_number(), 0, 16777216);
+
+    const boost::uint8_t r = (rgbval & 0xFF0000) >> 16;
+    const boost::uint8_t g = (rgbval & 0x00FF00) >> 8;
+    const boost::uint8_t b = rgbval & 0x0000FF;
+    boost::uint8_t a = 255;
+
+    if (fn.nargs > 1) {
         a = 255 * clamp<int>(toInt(fn.arg(1)), 0, 100) / 100;
-        IF_VERBOSE_ASCODING_ERRORS(
-        if ( fn.nargs > 2 )
-        {
-            std::stringstream ss; fn.dump_args(ss);
-            log_aserror(_("MovieClip.beginFill(%s): args after the "
-                    "first will be discarded"), ss.str());
-        }
-        );
     }
 
     rgba color(r, g, b, a);
 
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.beginFill(%d,%d,%d);"), movieclip->getTarget(), r, g, b);
-#endif
-    movieclip->beginFill(color);
+    const FillStyle f = SolidFill(color);
+    movieclip->graphics().beginFill(f);
 
     return as_value();
 }
@@ -1881,41 +1713,49 @@
         IF_VERBOSE_ASCODING_ERRORS(
         std::stringstream ss; fn.dump_args(ss);
         log_aserror(_("%s.beginGradientFill(%s): invalid call: 5 arguments "
-                "needed"),
-            movieclip->getTarget(), ss.str());
+                "needed"), movieclip->getTarget(), ss.str());
         );
         return as_value();
     }
 
-    // There are optional arguments that we do not implement!
-    if (fn.nargs > 5) {
-        std::stringstream ss; fn.dump_args(ss);
-        LOG_ONCE(log_unimpl(_("MovieClip.beginGradientFill(%s): args after "
-                        "the first five will be discarded"), ss.str()));
+    const size_t maxargs = getSWFVersion(fn) >= 8 ? 8 : 5;
+
+    if (fn.nargs > maxargs) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            std::stringstream ss; fn.dump_args(ss);
+            log_aserror(_("%s.beginGradientFill(%s): extra arguments "
+                    "invalidate call!"));
+            );
+        return as_value();
     }
 
-    bool radial = false;
+    GradientFill::Type t;
+
     std::string typeStr = fn.arg(0).to_string();
 
-    // Case-sensitive comparison needed for this ...
-    if (typeStr == "radial") radial = true;
-    else if (typeStr == "linear") radial = false;
+    // An unexpected fill type results in no fill in all versions.
+    if (typeStr == "radial") {
+        t = GradientFill::RADIAL;
+    }
+    else if (typeStr == "linear") {
+        t = GradientFill::LINEAR;
+    }
     else {
         IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.beginGradientFill(%s): first arg must be "
-            "'radial' or 'linear'"),
-            movieclip->getTarget(), ss.str());
-        );
+            std::stringstream ss; fn.dump_args(ss);
+            log_aserror(_("%s.beginGradientFill(%s): first arg must be "
+                "'radial', 'focal', or 'linear'"),
+                movieclip->getTarget(), ss.str());
+            );
         return as_value();
     }
 
     typedef boost::intrusive_ptr<as_object> ObjPtr;
-
-    ObjPtr colors = fn.arg(1).to_object(getGlobal(fn));
-    ObjPtr alphas = fn.arg(2).to_object(getGlobal(fn));
-    ObjPtr ratios = fn.arg(3).to_object(getGlobal(fn));
-    ObjPtr matrix = fn.arg(4).to_object(getGlobal(fn));
+    Global_as& gl = getGlobal(fn);
+    ObjPtr colors = fn.arg(1).to_object(gl);
+    ObjPtr alphas = fn.arg(2).to_object(gl);
+    ObjPtr ratios = fn.arg(3).to_object(gl);
+    ObjPtr matrix = fn.arg(4).to_object(gl);
 
     if (!colors || !alphas || !ratios || !matrix) {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -1954,23 +1794,6 @@
 
     SWFMatrix mat;
 
-    if (radial) {
-        // A gradient box extends from (-16384, -16384) to (16384, 16384),
-        // so we have set scale and translation to convert our radial
-        // (0, 0)-(64, 64) range to a -16384 - 16384 square.
-        mat.concatenate_translation(32, 32);
-        mat.set_scale(1 / 512., 1 / 512.);
-    }
-    else {
-        // A gradient box extends from (-16384, -16384) to (16384, 16384),
-        // so we have set scale and translation to convert our linear 0-256
-        // range to -16384 - 16384.
-        mat.concatenate_translation(128, 0);
-        mat.set_scale(1 / 128., 1 / 128.);
-    }
-
-    SWFMatrix input_matrix;
-
     // This is case sensitive.
     if (matrix->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box") {
         
@@ -1989,12 +1812,12 @@
         const double c = -std::sin(rot) * valW * 2;
         const double d = std::cos(rot) * valH * 2;
 
-        input_matrix.sx = a; 
-        input_matrix.shx = b;
-        input_matrix.shy = c;
-        input_matrix.sy = d; 
-        input_matrix.tx = valX + valW / 2.0;
-        input_matrix.ty = valY + valH / 2.0;
+        mat.sx = a; 
+        mat.shx = b;
+        mat.shy = c;
+        mat.sy = d; 
+        mat.tx = valX + valW / 2.0;
+        mat.ty = valY + valH / 2.0;
         
     }
     else {
@@ -2011,25 +1834,23 @@
         const boost::int32_t valTY = pixelsToTwips(
                 matrix->getMember(NSV::PROP_TY).to_number());
 
-        input_matrix.sx = valA; 
-        input_matrix.shx = valB;
-        input_matrix.shy = valC;
-        input_matrix.sy = valD; 
-        input_matrix.tx = valTX; 
-        input_matrix.ty = valTY;
+        mat.sx = valA; 
+        mat.shx = valB;
+        mat.shy = valC;
+        mat.sy = valD; 
+        mat.tx = valTX; 
+        mat.ty = valTY;
     }
     
-    mat.concatenate(input_matrix.invert());
-
     // ----------------------------
     // Create the gradients vector
     // ----------------------------
 
     string_table& st = getStringTable(fn);
 
-    std::vector<gradient_record> gradients;
+    std::vector<GradientRecord> gradients;
     gradients.reserve(stops);
-    for (size_t i=0; i < stops; ++i) {
+    for (size_t i = 0; i < stops; ++i) {
 
         string_table::key key = st.find(boost::lexical_cast<std::string>(i));
 
@@ -2053,7 +1874,7 @@
         const as_value& ratVal = ratios->getMember(key);
         const boost::uint32_t minRatio =
             gradients.empty() ? 0 :
-            std::min<boost::uint32_t>(gradients[i - 1].m_ratio + step, 0xff);
+            std::min<boost::uint32_t>(gradients[i - 1].ratio + step, 0xff);
 
         boost::uint8_t rat = ratVal.is_number() ? 
             clamp<boost::uint32_t>(toInt(ratVal), minRatio, 0xff) : minRatio;
@@ -2061,23 +1882,34 @@
         // The renderer may expect successively larger ratios; failure to
         // do this can lead to memory errors.
         if (!gradients.empty()) {
-            assert((rat != 0xff && rat > gradients[i - 1].m_ratio) ||
-                    (rat >= gradients[i - 1].m_ratio));
+            assert((rat != 0xff && rat > gradients[i - 1].ratio) ||
+                    (rat >= gradients[i - 1].ratio));
         }
 
         rgba color;
         color.parseRGB(col);
         color.m_a = alp;
 
-        gradients.push_back(gradient_record(rat, color));
-    }
-
-    if (radial) {
-        movieclip->beginRadialGradientFill(gradients, mat);
-    }
-    else {
-        movieclip->beginLinearGradientFill(gradients, mat);
-    }
+        gradients.push_back(GradientRecord(rat, color));
+    }
+
+    // Make sure we don't try to construct a GradientFill with only 1 stop!
+    if (stops < 2) {
+        const FillStyle f = SolidFill(gradients[0].color);
+        movieclip->graphics().beginFill(f);
+        return as_value();
+    }
+
+    GradientFill fd(t, mat.invert(), gradients);
+
+    /// TODO: set interpolation mode and spread mode.
+
+    /// Add a focus if present.
+    if (fn.nargs > 7) {
+        fd.setFocalPoint(fn.arg(7).to_number());
+    }
+
+    movieclip->graphics().beginFill(fd);
 
     return as_value();
 }

=== modified file 'libcore/swf/DefineButtonTag.cpp'
--- a/libcore/swf/DefineButtonTag.cpp   2010-06-11 07:04:03 +0000
+++ b/libcore/swf/DefineButtonTag.cpp   2010-08-01 07:47:27 +0000
@@ -428,8 +428,7 @@
     in.ensureBytes(2);
     _buttonLayer = in.read_u16();
 
-    // SWFMatrix::read() checks the length of the stream
-    _matrix.read(in);
+    _matrix = readSWFMatrix(in);
 
     if (t == SWF::DEFINEBUTTON2) {
         _cxform.read_rgba(in);

=== modified file 'libcore/swf/DefineEditTextTag.cpp'
--- a/libcore/swf/DefineEditTextTag.cpp 2010-07-09 07:37:30 +0000
+++ b/libcore/swf/DefineEditTextTag.cpp 2010-08-01 06:36:11 +0000
@@ -122,9 +122,8 @@
                 fontClassName);
        }
        
-       if (hasColor)
-       {
-               _color.read_rgba(in);
+       if (hasColor) {
+               _color = readRGBA(in);
        }
 
        if (hasMaxChars)

=== modified file 'libcore/swf/DefineMorphShapeTag.cpp'
--- a/libcore/swf/DefineMorphShapeTag.cpp       2010-07-28 07:57:23 +0000
+++ b/libcore/swf/DefineMorphShapeTag.cpp       2010-07-31 14:05:26 +0000
@@ -32,7 +32,7 @@
 #include "RunResources.h"
 #include "Global_as.h"
 #include "Renderer.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 
 namespace gnash {
 namespace SWF {
@@ -107,11 +107,10 @@
     // Next line will throw ParserException on malformed SWF
     const boost::uint16_t fillCount = in.read_variable_count();
     
-    fill_style fs1, fs2;
     for (size_t i = 0; i < fillCount; ++i) {
-        fs1.read(in, tag, md, r, &fs2);
-        _shape1.addFillStyle(fs1);
-        _shape2.addFillStyle(fs2);
+        OptionalFillPair fp = readFills(in, tag, md, true);
+        _shape1.addFillStyle(fp.first);
+        _shape2.addFillStyle(*fp.second);
     }
 
     const boost::uint16_t lineCount = in.read_variable_count();

=== modified file 'libcore/swf/DefineTextTag.cpp'
--- a/libcore/swf/DefineTextTag.cpp     2010-06-11 07:04:03 +0000
+++ b/libcore/swf/DefineTextTag.cpp     2010-08-01 07:47:27 +0000
@@ -101,7 +101,7 @@
        assert(tag == DEFINETEXT || tag == DEFINETEXT2);
 
        _rect.read(in);
-       _matrix.read(in);
+       _matrix = readSWFMatrix(in);
 
        in.ensureBytes(2); // glyph_bits + advance_bits
        int glyphBits = in.read_u8();

=== modified file 'libcore/swf/PlaceObject2Tag.cpp'
--- a/libcore/swf/PlaceObject2Tag.cpp   2010-05-20 09:57:10 +0000
+++ b/libcore/swf/PlaceObject2Tag.cpp   2010-08-01 07:47:27 +0000
@@ -52,7 +52,7 @@
 
     if (in.tell() < in.get_tag_end_position())
     {
-        m_matrix.read(in);
+        m_matrix = readSWFMatrix(in);
         m_has_flags2 |= HAS_MATRIX_MASK;
         if (in.tell() < in.get_tag_end_position())
         {
@@ -270,7 +270,7 @@
 
     if ( hasMatrix() )
     {
-        m_matrix.read(in);
+        m_matrix = readSWFMatrix(in);
     }
 
     if ( hasCxform() )
@@ -281,7 +281,7 @@
     if ( hasRatio() )
     {
         in.ensureBytes(2);
-        m_ratio = in.read_u16();
+        _ratio = in.read_u16();
     }
 
     if ( hasName() ) 
@@ -316,7 +316,7 @@
         {
             log_parse(_("  cxform: %s"), m_color_transform);
         }
-        if ( hasRatio() ) log_parse(_("  ratio: %d"), m_ratio);
+        if ( hasRatio() ) log_parse(_("  ratio: %d"), _ratio);
         if ( hasName() ) log_parse(_("  name = %s"), m_name.c_str());
         if ( hasClipDepth() ) log_parse(_("  clip_depth = %d (%d)"), 
m_clip_depth, m_clip_depth-DisplayObject::staticDepthOffset);
         log_parse(_(" m_place_type: %d"), getPlaceType() );
@@ -358,7 +358,7 @@
     }
 
     if (hasMatrix()) {
-        m_matrix.read(in);
+        m_matrix = readSWFMatrix(in);
     }
 
     if (hasCxform()) {
@@ -367,7 +367,7 @@
 
     if (hasRatio()) {
         in.ensureBytes(2);
-        m_ratio = in.read_u16();
+        _ratio = in.read_u16();
     }
     
     if (hasName()) {
@@ -423,7 +423,7 @@
         if (hasCharacter()) log_parse(_("  char id = %d"), _id);
         if (hasMatrix()) log_parse(_("  SWFMatrix: %s"), m_matrix);
         if (hasCxform()) log_parse(_("  cxform: %d"), m_color_transform);
-        if (hasRatio()) log_parse(_("  ratio: %d"), m_ratio);
+        if (hasRatio()) log_parse(_("  ratio: %d"), _ratio);
         if (hasName()) log_parse(_("  name = %s"), m_name);
         if (hasClassName()) log_parse(_("  class name = %s"), className);
         if (hasClipDepth()) log_parse(_("  clip_depth = %d (%d)"),

=== modified file 'libcore/swf/PlaceObject2Tag.h'
--- a/libcore/swf/PlaceObject2Tag.h     2010-06-11 14:05:12 +0000
+++ b/libcore/swf/PlaceObject2Tag.h     2010-07-31 16:16:52 +0000
@@ -73,7 +73,7 @@
 /// m_matrix:
 /// The SWFMatrix transform to apply to the newly created instance.
 ///
-/// m_ratio
+/// _ratio
 ///
 /// m_clip_depth:
 /// If != DisplayObject::noClipDepthValue, mark the created instance
@@ -94,7 +94,7 @@
         m_has_flags2(0),
         m_has_flags3(0),
         _id(0),
-        m_ratio(0),
+        _ratio(0),
         m_clip_depth(0),
         _blendMode(0),
         _movie_def(def)
@@ -116,7 +116,7 @@
         return m_has_flags2 & (HAS_CHARACTER_MASK | MOVE_MASK);
     } 
 
-    int getRatio()     const { return m_ratio; }
+    int getRatio()     const { return _ratio; }
     int getClipDepth() const { return m_clip_depth; }
     boost::uint16_t getID()        const { return _id; }
     const std::string& getName() const { return m_name; }
@@ -165,7 +165,7 @@
     boost::uint16_t _id;
     cxform  m_color_transform;
     SWFMatrix  m_matrix;
-    int     m_ratio;
+    int     _ratio;
     std::string m_name;
     int     m_clip_depth;
     

=== modified file 'libcore/swf/SWF.h'
--- a/libcore/swf/SWF.h 2010-07-24 14:38:36 +0000
+++ b/libcore/swf/SWF.h 2010-07-31 14:05:26 +0000
@@ -1514,9 +1514,9 @@
 /// SWF fill style types. Symbolic names copied from Ming.
 //
 /// For more info see:
-/// http://sswf.sourceforge.net/SWFalexref.html#swf_fill_style
-///
-enum fill_style_type {
+/// http://sswf.sourceforge.net/SWFalexref.html#swf_FillStyle
+enum FillType
+{
     FILL_SOLID                   = 0x00,
     FILL_LINEAR_GRADIENT         = 0x10,
     FILL_RADIAL_GRADIENT         = 0x12,
@@ -1529,18 +1529,19 @@
 
     /// swf8 (alexis is wrong), non-smoothed / hard edges
     FILL_CLIPPED_BITMAP_HARD     = 0x43
-
-};
-
-enum gradient_spread_mode {
-        GRADIENT_SPREAD_PAD,
-        GRADIENT_SPREAD_REFLECT,
-        GRADIENT_SPREAD_REPEAT
-};
-
-enum gradient_interpolation_mode {
-        GRADIENT_INTERPOL_NORMAL,
-        GRADIENT_INTERPOL_LINEAR
+};
+
+enum SpreadMode
+{
+    GRADIENT_SPREAD_PAD,
+    GRADIENT_SPREAD_REFLECT,
+    GRADIENT_SPREAD_REPEAT
+};
+
+enum InterpolationMode
+{
+    GRADIENT_INTERPOLATION_NORMAL,
+    GRADIENT_INTERPOLATION_LINEAR
 };
 
 

=== modified file 'libcore/swf/SetBackgroundColorTag.h'
--- a/libcore/swf/SetBackgroundColorTag.h       2010-05-20 09:57:10 +0000
+++ b/libcore/swf/SetBackgroundColorTag.h       2010-08-01 06:36:11 +0000
@@ -54,7 +54,7 @@
        void read(SWFStream& in)
        {
                // may throw ParserException
-               m_color.read_rgb(in);
+               m_color = readRGB(in);
 
                IF_VERBOSE_PARSE(
             log_parse(_("  SetBackgroundColor: %s"), m_color);

=== modified file 'libcore/swf/ShapeRecord.cpp'
--- a/libcore/swf/ShapeRecord.cpp       2010-07-29 06:24:31 +0000
+++ b/libcore/swf/ShapeRecord.cpp       2010-07-31 16:10:47 +0000
@@ -21,10 +21,9 @@
 #include "SWFStream.h"
 #include "movie_definition.h"
 #include "smart_ptr.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "Geometry.h"
 #include "GnashNumeric.h"
-#include "RunResources.h"
 #include "log.h"
 
 #include <vector>
@@ -35,9 +34,9 @@
 // Forward declarations
 namespace {
     void readFillStyles(ShapeRecord::FillStyles& styles, SWFStream& in,
-        SWF::TagType tag, movie_definition& md, const RunResources& r);
+        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);
+        SWF::TagType tag, movie_definition& md, const RunResources& /*r*/);
     void computeBounds(SWFRect& bounds, const ShapeRecord::Paths& paths,
         const ShapeRecord::LineStyles& lineStyles, int swfVersion);
 }
@@ -59,7 +58,7 @@
 
     void operator()(typename T::value_type& st)
     {
-        st.set_lerp(*_style1, *_style2, _ratio);
+        setLerp(st, *_style1, *_style2, _ratio);
         ++_style1, ++_style2;
     }
 
@@ -182,7 +181,7 @@
 }
 
 void
-ShapeRecord::addFillStyle(const fill_style& fs)
+ShapeRecord::addFillStyle(const FillStyle& fs)
 {
     _fillStyles.push_back(fs);
 }
@@ -224,8 +223,8 @@
         const Path& p1 = i < paths1.size() ? paths1[i] : empty_path;
         const Path& p2 = n < paths2.size() ? paths2[n] : empty_path;
 
-        const float new_ax = flerp(p1.ap.x, p2.ap.x, ratio);
-        const float new_ay = flerp(p1.ap.y, p2.ap.y, ratio);
+        const float new_ax = lerp<float>(p1.ap.x, p2.ap.x, ratio);
+        const float new_ay = lerp<float>(p1.ap.y, p2.ap.y, ratio);
 
         p.reset(new_ax, new_ay, p1.getLeftFill(),
                 p2.getRightFill(), p1.getLineStyle());
@@ -241,10 +240,10 @@
 
             const Edge& e2 = k < p2.size() ? p2[k] : empty_edge;
 
-            e.cp.x = static_cast<int>(flerp(e1.cp.x, e2.cp.x, ratio));
-            e.cp.y = static_cast<int>(flerp(e1.cp.y, e2.cp.y, ratio));
-            e.ap.x = static_cast<int>(flerp(e1.ap.x, e2.ap.x, ratio));
-            e.ap.y = static_cast<int>(flerp(e1.ap.y, e2.ap.y, ratio));
+            e.cp.x = static_cast<int>(lerp<float>(e1.cp.x, e2.cp.x, ratio));
+            e.cp.y = static_cast<int>(lerp<float>(e1.cp.y, e2.cp.y, ratio));
+            e.ap.x = static_cast<int>(lerp<float>(e1.ap.x, e2.ap.x, ratio));
+            e.ap.y = static_cast<int>(lerp<float>(e1.ap.y, e2.ap.y, ratio));
             ++k;
 
             if (p2.size() <= k) {
@@ -395,7 +394,7 @@
             }
             if ((flags & SHAPE_FILLSTYLE0_CHANGE) && num_fill_bits > 0)
             {
-                // fill_style_0_change = 1;
+                // FillStyle_0_change = 1;
                 if (! current_path.empty())
                 {
                     _paths.push_back(current_path);
@@ -446,7 +445,7 @@
             }
             if ((flags & SHAPE_FILLSTYLE1_CHANGE) && num_fill_bits > 0)
             {
-                // fill_style_1_change = 1;
+                // FillStyle_1_change = 1;
                 if (! current_path.empty())
                 {
                     _paths.push_back(current_path);
@@ -677,30 +676,29 @@
 // Read fill styles, and push them onto the given style array.
 void
 readFillStyles(ShapeRecord::FillStyles& styles, SWFStream& in,
-                 SWF::TagType tag, movie_definition& m, const RunResources& r)
+         SWF::TagType tag, movie_definition& m, const RunResources& /*r*/)
 {
     in.ensureBytes(1);
-    boost::uint16_t fill_style_count = in.read_u8();
+    boost::uint16_t FillStyle_count = in.read_u8();
     if (tag != SWF::DEFINESHAPE)
     {
-        if (fill_style_count == 0xFF)
+        if (FillStyle_count == 0xFF)
         {
             in.ensureBytes(2);
-            fill_style_count = in.read_u16();
+            FillStyle_count = in.read_u16();
         }
     }
 
     IF_VERBOSE_PARSE (
-        log_parse(_("  readFillStyles: count = %u"), fill_style_count);
+        log_parse(_("  readFillStyles: count = %u"), FillStyle_count);
     );
 
     // Read the styles.
-    styles.reserve(styles.size()+fill_style_count);
-    for (boost::uint16_t i = 0; i < fill_style_count; ++i) {
-        // TODO: add a fill_style constructor directly reading from stream
-        fill_style fs;
-        fs.read(in, tag, m, r);
-        styles.push_back(fs);
+    styles.reserve(styles.size()+FillStyle_count);
+    for (boost::uint16_t i = 0; i < FillStyle_count; ++i) {
+        // TODO: add a FillStyle constructor directly reading from stream
+        OptionalFillPair fp = readFills(in, tag, m, false);
+        styles.push_back(fp.first);
     }
 }
 

=== modified file 'libcore/swf/ShapeRecord.h'
--- a/libcore/swf/ShapeRecord.h 2010-07-29 06:24:31 +0000
+++ b/libcore/swf/ShapeRecord.h 2010-07-31 14:05:26 +0000
@@ -29,7 +29,7 @@
 namespace gnash {
     class movie_definition;
     class RunResources;
-    class fill_style;
+    class FillStyle;
 }
 
 namespace gnash {
@@ -52,7 +52,7 @@
 {
 public:
 
-    typedef std::vector<fill_style> FillStyles;
+    typedef std::vector<FillStyle> FillStyles;
     typedef std::vector<LineStyle> LineStyles;
     typedef std::vector<Path> Paths;
 
@@ -118,7 +118,7 @@
     /// Reset all shape data.
     void clear();
 
-    void addFillStyle(const fill_style& fs);
+    void addFillStyle(const FillStyle& fs);
 
     void addPath(const Path& path) {
         _paths.push_back(path);

=== modified file 'libcore/swf/TextRecord.cpp'
--- a/libcore/swf/TextRecord.cpp        2010-03-13 18:00:33 +0000
+++ b/libcore/swf/TextRecord.cpp        2010-08-01 06:36:11 +0000
@@ -81,8 +81,8 @@
 
     if (hasColor)
     {
-        if (tag == DEFINETEXT) _color.read_rgb(in);
-        else _color.read_rgba(in);
+        if (tag == DEFINETEXT) _color = readRGB(in);
+        else _color = readRGBA(in);
 
         IF_VERBOSE_PARSE(
             log_parse(_("  hasColor"));

=== modified file 'librender/Renderer.h'
--- a/librender/Renderer.h      2010-07-19 07:43:01 +0000
+++ b/librender/Renderer.h      2010-07-31 14:05:26 +0000
@@ -164,7 +164,7 @@
     class rgba;
     class SWFMatrix;
     class cxform;
-    class fill_style;
+    class FillStyle;
     class LineStyle;
 
     // XXX: GnashImageProxy (delayed image rendering)
@@ -219,7 +219,7 @@
     
     /// \brief
     /// Given an image, returns a pointer to a bitmap_info class
-    /// that can later be passed to fill_styleX_bitmap(), to set a
+    /// that can later be passed to FillStyleX_bitmap(), to set a
     /// bitmap fill style.
     virtual BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im) = 0;
 

=== modified file 'librender/Renderer_agg.cpp'
--- a/librender/Renderer_agg.cpp        2010-07-28 07:57:23 +0000
+++ b/librender/Renderer_agg.cpp        2010-07-31 15:15:34 +0000
@@ -127,7 +127,7 @@
 #include "GnashNumeric.h"
 #include "GC.h"
 #include "cxform.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 
 #ifdef HAVE_VA_VA_H
 #include "GnashVaapiImage.h"
@@ -670,6 +670,98 @@
     /// Whether smoothing is required.
     bool _smoothing;
 };    
+  
+
+/// Style handler
+//
+/// Transfer FillStyles to agg styles.
+struct StyleHandler : boost::static_visitor<>
+{
+    StyleHandler(SWFMatrix stage, SWFMatrix fill, const cxform& c,
+            agg_style_handler& sh, Quality q)
+        :
+        _stageMatrix(stage.invert()),
+        _fillMatrix(fill.invert()),
+        _cx(c),
+        _sh(sh),
+        _quality(q)
+    {}
+
+    void operator()(const GradientFill& f) const {
+          SWFMatrix m = f.matrix();
+          
+          m.concatenate(_fillMatrix);
+          m.concatenate(_stageMatrix);
+          switch (f.type()) {
+              case GradientFill::LINEAR:
+                  _sh.add_gradient_linear(f, m, _cx);
+                  break;
+              case GradientFill::RADIAL:
+                  if (f.focalPoint()) {
+                      _sh.add_gradient_focal(f, m, _cx);
+                  }
+                  else {
+                      _sh.add_gradient_radial(f, m, _cx);
+                  }
+                  break;
+          }
+    }
+
+    void operator()(const SolidFill& f) const {
+        const rgba color = _cx.transform(f.color());
+
+        // add the color to our self-made style handler (basically
+        // just a list)
+        _sh.add_color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b,
+                  color.m_a));
+    }
+
+    void operator()(const BitmapFill& f) const {
+        SWFMatrix m = f.matrix();
+        m.concatenate(_fillMatrix);
+        m.concatenate(_stageMatrix);
+
+        // Smoothing policy:
+        //
+        // - If unspecified, smooth when _quality >= BEST
+        // - If ON or forced, smooth when _quality > LOW
+        // - If OFF, don't smooth
+        //
+        // TODO: take a forceBitmapSmoothing parameter.
+        //       which should be computed by the VM looking
+        //       at MovieClip.forceSmoothing.
+        bool smooth = false;
+        if (_quality > QUALITY_LOW) {
+            // TODO: if forceSmoothing is true, smooth !
+            switch (f.smoothingPolicy()) {
+                case BitmapFill::SMOOTHING_UNSPECIFIED:
+                    if (_quality >= QUALITY_BEST) smooth = true;
+                    break;
+                case BitmapFill::SMOOTHING_ON:
+                    smooth = true;
+                    break;
+                default: break;
+            }
+        }
+
+        const bool tiled = (f.type() == BitmapFill::TILED);
+
+        _sh.add_bitmap(
+            dynamic_cast<const agg_bitmap_info*>(f.bitmap()), m, _cx, tiled,
+            smooth);
+    }
+
+private:
+
+    /// The inverted stage matrix.
+    const SWFMatrix _stageMatrix;
+    
+    /// The inverted fill matrix.
+    const SWFMatrix _fillMatrix;
+    const cxform& _cx;
+    agg_style_handler& _sh;
+    const Quality _quality;
+};  
             
 }
 
@@ -686,7 +778,7 @@
 public:
 
     // Given an image, returns a pointer to a bitmap_info class
-    // that can later be passed to fill_styleX_bitmap(), to set a
+    // that can later be passed to FillStyleX_bitmap(), to set a
     // bitmap fill style.
     gnash::BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im)
     {        
@@ -1030,12 +1122,11 @@
     AggPaths agg_paths;    
     buildPaths(agg_paths, paths);
  
-    // make sure m_single_fill_styles contains the required color 
-    need_single_fill_style(color);
+    std::vector<FillStyle> v(1, FillStyle(SolidFill(color)));
 
     // prepare style handler
     agg_style_handler sh;
-    build_agg_styles(sh, m_single_fill_styles, mat, cxform());
+    build_agg_styles(sh, v, mat, cxform());
     
     draw_shape(-1, paths, agg_paths, sh, false);
     
@@ -1119,7 +1210,7 @@
         drawShape(fillStyles, lineStyles, paths, worldMat, cx);
     }
 
-    void drawShape(const std::vector<fill_style>& fill_styles,
+    void drawShape(const std::vector<FillStyle>& FillStyles,
         const std::vector<LineStyle>& line_styles,
         const std::vector<Path>& objpaths, const SWFMatrix& mat,
         const cxform& cx)
@@ -1170,7 +1261,7 @@
 
         // prepare fill styles
         agg_style_handler sh;
-        if (have_shape) build_agg_styles(sh, fill_styles, mat, cx);
+        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);
@@ -1384,126 +1475,23 @@
     
     }
   } //buildPaths_rounded
-    
-  // Initializes the internal styles class for AGG renderer
-  void build_agg_styles(agg_style_handler& sh, 
-    const std::vector<fill_style>& fill_styles,
-    const SWFMatrix& fillstyle_matrix,
-    const cxform& cx) {
-    
-    SWFMatrix inv_stage_matrix = stage_matrix;
-    inv_stage_matrix.invert();
-    
-    const size_t fcount = fill_styles.size();
-    for (size_t fno=0; fno<fcount; ++fno) {
-    
-      int fill_type = fill_styles[fno].get_type();
-      
-      switch (fill_type) {
-
-        case SWF::FILL_LINEAR_GRADIENT:
-        {    
-          SWFMatrix m = fill_styles[fno].getGradientMatrix();
-          SWFMatrix cm = fillstyle_matrix;
-          cm.invert();
-          
-          m.concatenate(cm);
-          m.concatenate(inv_stage_matrix);
-          
-          sh.add_gradient_linear(fill_styles[fno], m, cx);
-          break;
-        } 
-
-        case SWF::FILL_RADIAL_GRADIENT:
-        {
-          SWFMatrix m = fill_styles[fno].getGradientMatrix();
-          SWFMatrix cm = fillstyle_matrix;
-          cm.invert();
-          
-          m.concatenate(cm);
-          m.concatenate(inv_stage_matrix);
-          
-          sh.add_gradient_radial(fill_styles[fno], m, cx);
-          break;
-        } 
-
-        case SWF::FILL_FOCAL_GRADIENT:
-        {
-          SWFMatrix m = fill_styles[fno].getGradientMatrix();
-          SWFMatrix cm = fillstyle_matrix;
-          cm.invert();
-          
-          m.concatenate(cm);
-          m.concatenate(inv_stage_matrix);
-          
-          sh.add_gradient_focal(fill_styles[fno], m, cx);
-          break;
-        }
-
-        case SWF::FILL_TILED_BITMAP:
-        case SWF::FILL_CLIPPED_BITMAP:
-        case SWF::FILL_TILED_BITMAP_HARD:
-        case SWF::FILL_CLIPPED_BITMAP_HARD:
-        {    
-          SWFMatrix m = fill_styles[fno].getBitmapMatrix();
-          SWFMatrix cm = fillstyle_matrix;
-          cm.invert();
-          
-          m.concatenate(cm);
-          m.concatenate(inv_stage_matrix);
-
-          //
-          // Smoothing policy:
-          //
-          // - If unspecified, smooth when _quality >= BEST
-          // - If ON or forced, smooth when _quality > LOW
-          // - If OFF, don't smooth
-          //
-          // TODO: take a forceBitmapSmoothing parameter.
-          //       which should be computed by the VM looking
-          //       at MovieClip.forceSmoothing.
-          //
-          bool smooth = false;
-          if ( _quality > QUALITY_LOW ) // never smooth in LOW quality
-          {
-             // TODO: if forceSmoothing is true, smooth !
-             switch ( fill_styles[fno].getBitmapSmoothingPolicy() )
-             {
-                case fill_style::BITMAP_SMOOTHING_UNSPECIFIED:
-                    if ( _quality >= QUALITY_BEST ) smooth = true;
-                    break;
-                case fill_style::BITMAP_SMOOTHING_ON:
-                    smooth = true;
-                    break;
-                default: break;
-             }
-          }
-
-          sh.add_bitmap(dynamic_cast<const agg_bitmap_info*> 
-            (fill_styles[fno].get_bitmap_info(*this)), m, cx, 
-            (fill_type==SWF::FILL_TILED_BITMAP) ||
-            (fill_type==SWF::FILL_TILED_BITMAP_HARD),
-            smooth);
-
-          break;
-        } 
-
-        case SWF::FILL_SOLID:
-        default:
-        {            
-          rgba color = cx.transform(fill_styles[fno].get_color());
-
-          // add the color to our self-made style handler (basically
-          // just a list)
-          sh.add_color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b,
-                      color.m_a));
-        } 
-        
-      } // switch
-        
-    } // for
-    
-  } //build_agg_styles
+
+    // Initializes the internal styles class for AGG renderer
+    void build_agg_styles(agg_style_handler& sh,
+        const std::vector<FillStyle>& FillStyles,
+        const SWFMatrix& fillstyle_matrix, const cxform& cx) {
+    
+        SWFMatrix inv_stage_matrix = stage_matrix;
+        inv_stage_matrix.invert();
+    
+        const size_t fcount = FillStyles.size();
+
+        for (size_t fno = 0; fno < fcount; ++fno) {
+            const StyleHandler st(stage_matrix, fillstyle_matrix, cx, sh,
+                    _quality);
+            boost::apply_visitor(st, FillStyles[fno].fill);
+        } 
+    } 
   
 
   /// Draws the given path using the given fill style and color transform.
@@ -2154,20 +2142,6 @@
   
 private:  // private variables
     
-  /// Sets m_single_fill_styles to one solid fill with the given color 
-    void need_single_fill_style(const rgba& color)
-    {
-
-        if (m_single_fill_styles.size() == 0)
-        { 
-            fill_style dummy;
-            m_single_fill_styles.push_back(dummy);
-        }
-
-        m_single_fill_styles[0].set_color(color);
-
-    } 
-
     typedef agg::renderer_base<PixelFormat> renderer_base;
 
     // renderer base
@@ -2198,7 +2172,7 @@
     AlphaMasks _alphaMasks;
     
     /// Cached fill style list with just one entry used for font rendering
-    std::vector<fill_style> m_single_fill_styles;
+    std::vector<FillStyle> m_single_FillStyles;
 
 
 };

=== modified file 'librender/Renderer_agg_style.h'
--- a/librender/Renderer_agg_style.h    2010-01-13 07:54:28 +0000
+++ b/librender/Renderer_agg_style.h    2010-07-31 16:32:49 +0000
@@ -179,9 +179,8 @@
 {
 public:
 
-  agg_style_gradient(const gnash::fill_style& fs,
-        const gnash::SWFMatrix& mat, const gnash::cxform& cx,
-        int norm_size)
+  agg_style_gradient(const GradientFill& fs, const SWFMatrix& mat,
+          const cxform& cx, int norm_size)
     :
     agg_style_base(false),
     m_cx(cx),
@@ -196,7 +195,7 @@
     // Build gradient lookup table
     m_gradient_lut.remove_all(); 
     
-    const size_t size = fs.get_color_stop_count();
+    const size_t size = fs.recordCount();
     
     // It is essential that at least two colours are added; otherwise agg
     // will use uninitialized values.
@@ -204,11 +203,11 @@
 
     for (int i = 0; i != size; ++i) {
     
-      const gradient_record& gr = fs.get_color_stop(i); 
-      rgba trans_color = m_cx.transform(gr.m_color);
+      const GradientRecord& gr = fs.record(i); 
+      rgba trans_color = m_cx.transform(gr.color);
       if (trans_color.m_a < 255) m_need_premultiply = true;    
       
-      m_gradient_lut.add_color(gr.m_ratio/255.0, agg::rgba8(trans_color.m_r, 
+      m_gradient_lut.add_color(gr.ratio/255.0, agg::rgba8(trans_color.m_r, 
         trans_color.m_g, trans_color.m_b, trans_color.m_a));
         
     } // for
@@ -572,7 +571,7 @@
     
     // === GRADIENT ===
 
-    void add_gradient_linear(const gnash::fill_style& fs,
+    void add_gradient_linear(const GradientFill& fs,
         const gnash::SWFMatrix& mat, const gnash::cxform& cx)
     {
     
@@ -601,7 +600,7 @@
     }
     
 
-    void add_gradient_radial(const gnash::fill_style& fs,
+    void add_gradient_radial(const GradientFill& fs,
         const gnash::SWFMatrix& mat, const gnash::cxform& cx)
     {
     
@@ -636,7 +635,7 @@
       m_styles.push_back(st);
     }
 
-    void add_gradient_focal(const gnash::fill_style& fs,
+    void add_gradient_focal(const GradientFill& fs,
         const gnash::SWFMatrix& mat, const gnash::cxform& cx)
     {
       typedef agg::rgba8 color_type;
@@ -662,7 +661,7 @@
       
       // re-initialize focal gradient settings
       gradient_adaptor_type& adaptor = st->get_gradient_adaptor();
-      adaptor.init(32.0, fs.get_focal_point()*32.0, 0.0);
+      adaptor.init(32.0, fs.focalPoint() * 32.0, 0.0);
     
       m_styles.push_back(st);
     }

=== modified file 'librender/Renderer_cairo.cpp'
--- a/librender/Renderer_cairo.cpp      2010-07-28 07:57:23 +0000
+++ b/librender/Renderer_cairo.cpp      2010-07-31 16:32:49 +0000
@@ -42,7 +42,7 @@
 #include "swf/ShapeRecord.h"
 #include "Renderer_cairo.h"
 #include "utility.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 
 #include <cmath>
 #include <cairo/cairo.h>
@@ -51,80 +51,14 @@
 
 namespace gnash {
 
-// Converts from RGB image to 32-bit pixels in CAIRO_FORMAT_RGB24 format
-static void
-rgb_to_cairo_rgb24(boost::uint8_t* dst, const GnashImage* im)
-{
-    boost::uint32_t* dst32 = reinterpret_cast<boost::uint32_t*>(dst);
-    for (size_t y = 0;  y < im->height();  y++)
-    {
-        const boost::uint8_t* src = im->scanlinePointer(y);
-        for (size_t x = 0;  x < im->width();  x++, src += 3) {
-            *dst32++ = (src[0] << 16) | (src[1] << 8) | src[2];
-        }
-    }
-}
-
-// Converts from RGBA image to 32-bit pixels in CAIRO_FORMAT_ARGB32 format
-static void
-rgba_to_cairo_argb(boost::uint8_t* dst, const GnashImage* im)
-{
-    boost::uint32_t* dst32 = reinterpret_cast<boost::uint32_t*>(dst);
-    for (size_t y = 0;  y < im->height();  y++)
-    {
-        const boost::uint8_t* src = im->scanlinePointer(y);
-        for (size_t x = 0;  x < im->width();  x++, src += 4)
-        {
-            const boost::uint8_t& r = src[0],
-                                  g = src[1],
-                                  b = src[2],
-                                  a = src[3];
-
-            if (a) {  
-                *dst32++ = (a << 24) | (r << 16) | (g << 8) | b;       
-            } else {
-                *dst32++ = 0;
-            }
-        }
-    }
-}
-
-
-static void
-snap_to_half_pixel(cairo_t* cr, double& x, double& y)
-{
-    cairo_user_to_device(cr, &x, &y);
-
-    x = std::floor(x + 0.5) + 0.5;
-    y = std::floor(y + 0.5) + 0.5;
-
-    cairo_device_to_user(cr, &x, &y);
-}
-
-static void
-init_cairo_matrix(cairo_matrix_t* cairo_matrix, const SWFMatrix& gnash_matrix)
-{
-    cairo_matrix_init(cairo_matrix,
-                      gnash_matrix.sx/65536.0, gnash_matrix.shx/65536.0,
-                      gnash_matrix.shy/65536.0, gnash_matrix.sy/65536.0,
-                      gnash_matrix.tx, gnash_matrix.ty);
-}
-
-void
-pattern_add_color_stops(const fill_style& style, cairo_pattern_t* pattern,
-                        const cxform& cx)
-{      
-    for (size_t index = 0; index < style.get_color_stop_count(); ++index) {
-        const gradient_record& grad = style.get_color_stop(index);
-        
-        rgba c = cx.transform(grad.m_color);
-
-        cairo_pattern_add_color_stop_rgba (pattern,
-            grad.m_ratio / 255.0, c.m_r / 255.0, c.m_g / 255.0,
-            c.m_b / 255.0, c.m_a / 255.0);
-    }
-}
-
+namespace {
+    void pattern_add_color_stops(const GradientFill& f,
+            cairo_pattern_t* pattern, const cxform& cx);
+    void init_cairo_matrix(cairo_matrix_t* cairo_matrix,
+            const SWFMatrix& gnash_matrix);
+}
+
+namespace {
 
 class bitmap_info_cairo : public BitmapInfo, boost::noncopyable
 {
@@ -187,86 +121,147 @@
     cairo_pattern_t* _pattern;
 };
 
+
+/// Style handler
+//
+/// Transfer FillStyles to agg styles.
+struct StyleHandler : boost::static_visitor<cairo_pattern_t*>
+{
+    StyleHandler(const cxform& c)
+        :
+        _cx(c)
+    {}
+
+    cairo_pattern_t* operator()(const GradientFill& f) const {
+        const SWFMatrix m = f.matrix();
+        switch (f.type()) {
+            case GradientFill::LINEAR:
+            {
+                cairo_matrix_t mat;
+                init_cairo_matrix(&mat, m);
+      
+                cairo_pattern_t* pattern =
+                    cairo_pattern_create_linear(0, 0, 256.0, 0);
+                cairo_pattern_set_matrix (pattern, &mat);
+
+                pattern_add_color_stops(f, pattern, _cx);
+                return pattern;
+            }
+            case GradientFill::RADIAL:
+            {
+              
+                // Undo the translation our parser applied.
+                gnash::SWFMatrix transl;
+                transl.concatenate_translation(-32, -32);
+                transl.concatenate(m);
+
+                cairo_matrix_t mat;
+                init_cairo_matrix(&mat, transl);
+
+                /// This is 0 for radial gradients.
+                const double focal_pos = 32.0f * f.focalPoint();
+
+                cairo_pattern_t* pattern =
+                    cairo_pattern_create_radial(focal_pos, 0.0, 0.0,
+                            0.0, 0.0, 32.0f);
+
+                cairo_pattern_set_matrix (pattern, &mat);          
+              
+                pattern_add_color_stops(f, pattern, _cx);
+                return pattern;
+            }
+        }
+        // We should never get here.
+        return 0;
+    }
+
+    cairo_pattern_t* operator()(const SolidFill& f) const {
+        rgba c = _cx.transform(f.color());
+        cairo_pattern_t* pattern =
+            cairo_pattern_create_rgba(c.m_r / 255.0, c.m_g / 255.0,
+                                    c.m_b / 255.0, c.m_a / 255.0);
+        return pattern;
+    }
+
+    cairo_pattern_t* operator()(const BitmapFill& f) const {
+        SWFMatrix m = f.matrix();
+      
+        const bitmap_info_cairo* binfo =
+            dynamic_cast<const bitmap_info_cairo*>(f.bitmap());
+
+        if (!binfo) return 0;
+      
+        cairo_matrix_t mat;
+        init_cairo_matrix(&mat, m);       
+
+        // TODO: the second argument should be fill_type but is unused.
+        cairo_pattern_t* pattern = binfo->apply(&mat, 0);
+        return pattern;
+    }
+
+private:
+    const cxform& _cx;
+};  
+
+}
+
+// Converts from RGB image to 32-bit pixels in CAIRO_FORMAT_RGB24 format
+static void
+rgb_to_cairo_rgb24(boost::uint8_t* dst, const GnashImage* im)
+{
+    boost::uint32_t* dst32 = reinterpret_cast<boost::uint32_t*>(dst);
+    for (size_t y = 0;  y < im->height();  y++)
+    {
+        const boost::uint8_t* src = im->scanlinePointer(y);
+        for (size_t x = 0;  x < im->width();  x++, src += 3) {
+            *dst32++ = (src[0] << 16) | (src[1] << 8) | src[2];
+        }
+    }
+}
+
+// Converts from RGBA image to 32-bit pixels in CAIRO_FORMAT_ARGB32 format
+static void
+rgba_to_cairo_argb(boost::uint8_t* dst, const GnashImage* im)
+{
+    boost::uint32_t* dst32 = reinterpret_cast<boost::uint32_t*>(dst);
+    for (size_t y = 0;  y < im->height();  y++)
+    {
+        const boost::uint8_t* src = im->scanlinePointer(y);
+        for (size_t x = 0;  x < im->width();  x++, src += 4)
+        {
+            const boost::uint8_t& r = src[0],
+                                  g = src[1],
+                                  b = src[2],
+                                  a = src[3];
+
+            if (a) {  
+                *dst32++ = (a << 24) | (r << 16) | (g << 8) | b;       
+            } else {
+                *dst32++ = 0;
+            }
+        }
+    }
+}
+
+
+static void
+snap_to_half_pixel(cairo_t* cr, double& x, double& y)
+{
+    cairo_user_to_device(cr, &x, &y);
+
+    x = std::floor(x + 0.5) + 0.5;
+    y = std::floor(y + 0.5) + 0.5;
+
+    cairo_device_to_user(cr, &x, &y);
+}
+
 static cairo_pattern_t*
-get_cairo_pattern(Renderer_cairo& renderer, const fill_style& style, const 
cxform& cx)
+get_cairo_pattern(const FillStyle& style, const cxform& cx)
 {
-  int fill_type = style.get_type();
-  cairo_pattern_t* pattern = NULL;
-      
-  switch (fill_type) {
-
-    case SWF::FILL_LINEAR_GRADIENT:
-    {
-      SWFMatrix m = style.getGradientMatrix();
-    
-      cairo_matrix_t mat;
-      init_cairo_matrix(&mat, m);
-      
-      pattern = cairo_pattern_create_linear(0, 0, 256.0, 0);
-      cairo_pattern_set_matrix (pattern, &mat);
-
-      pattern_add_color_stops(style, pattern, cx);
-                                                  
-      break;
-    }
-    case SWF::FILL_RADIAL_GRADIENT:
-    case SWF::FILL_FOCAL_GRADIENT:
-    {
-      SWFMatrix m = style.getGradientMatrix();
-      
-      // Undo the translation our parser applied.
-      gnash::SWFMatrix transl;
-      transl.concatenate_translation(-32, -32);
-      transl.concatenate(m);
-
-      cairo_matrix_t mat;
-      init_cairo_matrix(&mat, transl);
-
-      double focal_pos = 0;
-
-      if (fill_type == SWF::FILL_FOCAL_GRADIENT) {
-        focal_pos = 32.0f * style.get_focal_point();
-      }
-
-      pattern = cairo_pattern_create_radial(focal_pos, 0.0, 0.0, 0.0, 0.0, 
32.0f);
-
-      cairo_pattern_set_matrix (pattern, &mat);          
-      
-      pattern_add_color_stops(style, pattern, cx);
-      break;
-    }
-    case SWF::FILL_TILED_BITMAP_HARD:
-    case SWF::FILL_TILED_BITMAP:
-    case SWF::FILL_CLIPPED_BITMAP:
-    case SWF::FILL_CLIPPED_BITMAP_HARD:
-    {
-      SWFMatrix m = style.getBitmapMatrix();        
-      
-      const bitmap_info_cairo* binfo
-        = dynamic_cast<const 
bitmap_info_cairo*>(style.get_bitmap_info(renderer));
-
-      if (!binfo) {
-        return NULL;
-      }
-      
-      cairo_matrix_t mat;
-      init_cairo_matrix(&mat, m);       
-
-      pattern = binfo->apply(&mat, fill_type);
-      break;
-    } 
-
-    case SWF::FILL_SOLID:
-    {            
-      rgba c = cx.transform(style.get_color());
-      pattern = cairo_pattern_create_rgba (c.m_r / 255.0, c.m_g / 255.0,
-                                            c.m_b / 255.0, c.m_a / 255.0);
-      break;
-    }
-    
-  } // switch
+    StyleHandler st(cx);
+    cairo_pattern_t* pattern = boost::apply_visitor(st, style.fill);
   
-  return pattern;
+    return pattern;
 
 }
 
@@ -275,24 +270,24 @@
 public:
   CairoPathRunner(Renderer_cairo& renderer,
                   const std::vector<Path>& paths,
-                  const std::vector<fill_style>& fill_styles, cairo_t* context)
-  : PathParser(paths, fill_styles.size()),
+                  const std::vector<FillStyle>& FillStyles, cairo_t* context)
+  : PathParser(paths, FillStyles.size()),
     _renderer(renderer),
     _cr(context),
     _pattern(0),
-    _fill_styles(fill_styles)
+    _FillStyles(FillStyles)
   {
   }
   
   virtual void prepareFill(int fill_index, const cxform& cx)
   {
     if (!_pattern) {
-      _pattern = get_cairo_pattern(_renderer, _fill_styles[fill_index-1], cx);
+      _pattern = get_cairo_pattern(_FillStyles[fill_index-1], cx);
     }
   }
-  virtual void terminateFill(int fill_style)
+  virtual void terminateFill(int FillStyle)
   {
-    UNUSED(fill_style);
+    UNUSED(FillStyle);
 
     if (!_pattern) {
       cairo_new_path(_cr);
@@ -356,7 +351,7 @@
   Renderer_cairo& _renderer;
   cairo_t* _cr;
   cairo_pattern_t* _pattern;
-  const std::vector<fill_style>& _fill_styles;
+  const std::vector<FillStyle>& _FillStyles;
 };
 
 
@@ -870,10 +865,10 @@
 void
 Renderer_cairo::draw_subshape(const PathVec& path_vec, const SWFMatrix& mat,
                               const cxform& cx,
-                              const std::vector<fill_style>& fill_styles,
+                              const std::vector<FillStyle>& FillStyles,
                               const std::vector<LineStyle>& line_styles)
 { 
-    CairoPathRunner runner(*this, path_vec, fill_styles, _cr);
+    CairoPathRunner runner(*this, path_vec, FillStyles, _cr);
     runner.run(cx, mat);
 
     draw_outlines(path_vec, line_styles, cx, mat);
@@ -961,7 +956,7 @@
 
     std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
     
-    const std::vector<fill_style>& fill_styles = shape.fillStyles();
+    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) {
@@ -973,7 +968,7 @@
             subshape_paths.push_back(*subshapes[i]);
         }
         
-        draw_subshape(subshape_paths, mat, cx, fill_styles,
+        draw_subshape(subshape_paths, mat, cx, FillStyles,
                       line_styles);
     }
 }
@@ -983,10 +978,9 @@
                           const SWFMatrix& mat)
 {
     cxform dummy_cx;
-    std::vector<fill_style> glyph_fs;
+    std::vector<FillStyle> glyph_fs;
     
-    fill_style coloring;
-    coloring.setSolid(color);
+    FillStyle coloring = FillStyle(SolidFill(color));
     
     glyph_fs.push_back(coloring);
     
@@ -1082,6 +1076,35 @@
     return true;
 }
 
+namespace {
+
+void
+pattern_add_color_stops(const GradientFill& f, cairo_pattern_t* pattern,
+                        const cxform& cx)
+{      
+    for (size_t index = 0; index < f.recordCount(); ++index) {
+        const GradientRecord& grad = f.record(index);
+        
+        rgba c = cx.transform(grad.color);
+
+        cairo_pattern_add_color_stop_rgba (pattern,
+            grad.ratio / 255.0, c.m_r / 255.0, c.m_g / 255.0,
+            c.m_b / 255.0, c.m_a / 255.0);
+    }
+}
+
+void
+init_cairo_matrix(cairo_matrix_t* cairo_matrix, const SWFMatrix& gnash_matrix)
+{
+    cairo_matrix_init(cairo_matrix,
+                      gnash_matrix.sx/65536.0, gnash_matrix.shx/65536.0,
+                      gnash_matrix.shy/65536.0, gnash_matrix.sy/65536.0,
+                      gnash_matrix.tx, gnash_matrix.ty);
+}
+
+
+}
+
 
 namespace renderer {
 namespace cairo {

=== modified file 'librender/Renderer_cairo.h'
--- a/librender/Renderer_cairo.h        2010-07-19 07:43:01 +0000
+++ b/librender/Renderer_cairo.h        2010-07-31 14:05:26 +0000
@@ -87,7 +87,7 @@
 
     void draw_subshape(const PathVec& path_vec,
                        const SWFMatrix& mat, const cxform& cx,
-                       const std::vector<fill_style>& fill_styles,
+                       const std::vector<FillStyle>& FillStyles,
                        const std::vector<LineStyle>& line_styles);
 
     void draw_mask(const PathVec& path_vec);

=== modified file 'librender/Renderer_ogl.cpp'
--- a/librender/Renderer_ogl.cpp        2010-07-28 07:57:23 +0000
+++ b/librender/Renderer_ogl.cpp        2010-07-31 16:32:49 +0000
@@ -35,7 +35,7 @@
 #include "utility.h"
 #include "Range2d.h"
 #include "cxform.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 
 #if defined(_WIN32) || defined(WIN32)
 #  include <Windows.h>
@@ -109,6 +109,53 @@
 
 namespace gnash {
 
+namespace {
+    const BitmapInfo* createGradientBitmap(const GradientFill& gf,
+            Renderer& renderer);
+}
+
+namespace {
+
+/// Style handler
+//
+/// Transfer FillStyles to the ogl renderer.
+struct StyleHandler : boost::static_visitor<>
+{
+    StyleHandler(const cxform& c, Renderer& r)
+        :
+        _cx(c),
+        _renderer(r)
+    {}
+
+    void operator()(const GradientFill& f) const {
+
+        const bitmap_info_ogl* binfo = static_cast<const bitmap_info_ogl*>(
+            createGradientBitmap(f, _renderer));  
+
+        SWFMatrix m = f.matrix();
+        binfo->apply(m, bitmap_info_ogl::WRAP_CLAMP); 
+    }
+
+    void operator()(const SolidFill& f) const {
+        const rgba c = _cx.transform(f.color());
+        glColor4ub(c.m_r, c.m_g, c.m_b, c.m_a);
+    }
+
+    void operator()(const BitmapFill& f) const {
+        const bitmap_info_ogl* binfo = static_cast<const bitmap_info_ogl*>(
+                   f.bitmap());
+        binfo->apply(f.matrix(), f.type() == BitmapFill::TILED ?
+                bitmap_info_ogl::WRAP_REPEAT : bitmap_info_ogl::WRAP_CLAMP);
+    }
+
+private:
+    const cxform& _cx;
+    Renderer& _renderer;
+};  
+
+}
+
+
 #ifdef OSMESA_TESTING
 
 class OSRenderMesa : public boost::noncopyable
@@ -1094,10 +1141,9 @@
   add_paths(const PathVec& path_vec)
   {
     cxform dummy_cx;
-    std::vector<fill_style> dummy_fs;
+    std::vector<FillStyle> dummy_fs;
     
-    fill_style coloring;
-    coloring.setSolid(rgba(0,0,0,0));
+    FillStyle coloring = FillStyle(SolidFill(rgba(0, 0, 0, 0)));
     
     dummy_fs.push_back(coloring);
     
@@ -1299,63 +1345,10 @@
     }    
   }
 
-  void apply_fill_style(const fill_style& style, const SWFMatrix& /* mat */, 
const cxform& cx)
+  void apply_FillStyle(const FillStyle& style, const SWFMatrix& /* mat */, 
const cxform& cx)
   {
-      int fill_type = style.get_type();
-      
-      rgba c = cx.transform(style.get_color());
-
-      glColor4ub(c.m_r, c.m_g, c.m_b, c.m_a);
-          
-          
-      switch (fill_type) {
-
-        case SWF::FILL_LINEAR_GRADIENT:
-        case SWF::FILL_RADIAL_GRADIENT:
-        case SWF::FILL_FOCAL_GRADIENT:
-        {
-                    
-          const bitmap_info_ogl* binfo = static_cast<const bitmap_info_ogl*>(
-                      style.need_gradient_bitmap(*this));       
-
-          SWFMatrix m = style.getGradientMatrix();
-          
-          binfo->apply(m, bitmap_info_ogl::WRAP_CLAMP); 
-          
-          break;
-        }        
-        case SWF::FILL_TILED_BITMAP_HARD:
-        case SWF::FILL_TILED_BITMAP:
-        {
-            const bitmap_info_ogl* binfo = static_cast<const bitmap_info_ogl*>(
-                    style.get_bitmap_info(*this));
-
-          binfo->apply(style.getBitmapMatrix(), bitmap_info_ogl::WRAP_REPEAT);
-          break;
-        }
-                
-        case SWF::FILL_CLIPPED_BITMAP:
-        // smooth=true;
-        case SWF::FILL_CLIPPED_BITMAP_HARD:
-        {     
-          const bitmap_info_ogl* binfo = dynamic_cast<const bitmap_info_ogl*>(
-                  style.get_bitmap_info(*this));
-          
-          assert(binfo);
-
-          binfo->apply(style.getBitmapMatrix(), bitmap_info_ogl::WRAP_CLAMP);
-          
-          break;
-        } 
-
-        case SWF::FILL_SOLID:
-        {
-          rgba c = cx.transform(style.get_color());
-
-          glColor4ub(c.m_r, c.m_g, c.m_b, c.m_a);
-        }
-        
-      } // switch
+      const StyleHandler st(cx, *this);
+      boost::apply_visitor(st, style.fill);
   }
   
   
@@ -1364,7 +1357,7 @@
   {
   //  GNASH_REPORT_FUNCTION;
      
-    // In case GL_TEXTURE_2D was enabled by apply_fill_style(), disable it now.
+    // In case GL_TEXTURE_2D was enabled by apply_FillStyle(), disable it now.
     // FIXME: this sucks
     glDisable(GL_TEXTURE_2D);
     
@@ -1462,7 +1455,7 @@
   void
   draw_outlines(const PathVec& path_vec, const PathPointMap& pathpoints,
                const SWFMatrix& mat, const cxform& cx,
-               const std::vector<fill_style>& /* fill_styles */,
+               const std::vector<FillStyle>& /* FillStyles */,
                 const std::vector<LineStyle>& line_styles)
   {
   
@@ -1626,13 +1619,13 @@
   draw_subshape(const PathVec& path_vec,
     const SWFMatrix& mat,
     const cxform& cx,
-    const std::vector<fill_style>& fill_styles,
+    const std::vector<FillStyle>& FillStyles,
     const std::vector<LineStyle>& line_styles)
   {
     PathVec normalized = normalize_paths(path_vec);
     PathPointMap pathpoints = getPathPoints(normalized);
     
-    for (size_t i = 0; i < fill_styles.size(); ++i) {
+    for (size_t i = 0; i < FillStyles.size(); ++i) {
       PathPtrVec paths = paths_by_style(normalized, i+1);
       
       if (!paths.size()) {
@@ -1662,20 +1655,25 @@
         _tesselator.endContour();
       }
       
-
-      
-      apply_fill_style(fill_styles[i], mat, cx);
-
-      if (fill_styles[i].get_type() != SWF::FILL_SOLID) {     
-        // Apply alpha premultiplication.
-        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+      apply_FillStyle(FillStyles[i], mat, cx);
+
+      // This is terrible, but since the renderer is half dead I don't care.
+      try {
+          boost::get<SolidFill>(FillStyles[i].fill);
+      }
+      catch (const boost::bad_get&) {
+          // For non solid fills...
+          glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
       }
       
       _tesselator.tesselate();
       
-      if (fill_styles[i].get_type() != SWF::FILL_SOLID) {    
-        // restore to original.
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      try {
+          boost::get<SolidFill>(FillStyles[i].fill);
+      }
+      catch (const boost::bad_get&) {
+          // Restore to original.
+          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       }
       
       glDisable(GL_TEXTURE_GEN_S);
@@ -1684,7 +1682,7 @@
       glDisable(GL_TEXTURE_2D);      
     }
     
-    draw_outlines(normalized, pathpoints, mat, cx, fill_styles, line_styles);
+    draw_outlines(normalized, pathpoints, mat, cx, FillStyles, line_styles);
   }
   
 // Drawing procedure:
@@ -1731,7 +1729,7 @@
 
     std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
     
-    const std::vector<fill_style>& fill_styles = shape.fillStyles();
+    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) {
@@ -1743,7 +1741,7 @@
         subshape_paths.push_back(*subshapes[i]);
       }
       
-      draw_subshape(subshape_paths, mat, cx, fill_styles,
+      draw_subshape(subshape_paths, mat, cx, FillStyles,
                     line_styles);
     }
   }
@@ -1753,10 +1751,9 @@
   {
     if (_drawing_mask) abort();
     cxform dummy_cx;
-    std::vector<fill_style> glyph_fs;
+    std::vector<FillStyle> glyph_fs;
     
-    fill_style coloring;
-    coloring.setSolid(c);
+    FillStyle coloring = FillStyle(SolidFill(c));
     
     glyph_fs.push_back(coloring);
     
@@ -1842,16 +1839,110 @@
   }
   return renderer;
 }
-  
-  
+ 
+namespace {
+
+// TODO: this function is rubbish and shouldn't survive a rewritten OGL
+// renderer.
+rgba
+sampleGradient(const GradientFill& fill, boost::uint8_t ratio)
+{
+
+    // By specs, first gradient should *always* be 0, 
+    // anyway a malformed SWF could break this,
+    // so we cannot rely on that information...
+    if (ratio < fill.record(0).ratio) {
+        return fill.record(0).color;
+    }
+
+    if (ratio >= fill.record(fill.recordCount() - 1).ratio) {
+        return fill.record(fill.recordCount() - 1).color;
+    }
+        
+    for (size_t i = 1, n = fill.recordCount(); i < n; ++i) {
+
+        const GradientRecord& gr1 = fill.record(i);
+        if (gr1.ratio < ratio) continue;
+
+        const GradientRecord& gr0 = fill.record(i - 1);
+        if (gr0.ratio > ratio) continue;
+
+        float f = 0.0f;
+
+        if (gr0.ratio != gr1.ratio) {
+            f = (ratio - gr0.ratio) / float(gr1.ratio - gr0.ratio);
+        }
+        else {
+            // Ratios are equal IFF first and second GradientRecord
+            // have the same ratio. This would be a malformed SWF.
+            IF_VERBOSE_MALFORMED_SWF(
+                log_swferror(_("two gradients in a FillStyle "
+                    "have the same position/ratio: %d"),
+                    gr0.ratio);
+            );
+        }
+
+        rgba result;
+        result.set_lerp(gr0.color, gr1.color, f);
+        return result;
+    }
+
+    // Assuming gradients are ordered by ratio? see start comment
+    return fill.record(fill.recordCount() - 1).color;
+}
+
+const BitmapInfo*
+createGradientBitmap(const GradientFill& gf, Renderer& renderer)
+{
+    std::auto_ptr<ImageRGBA> im;
+
+    switch (gf.type())
+    {
+        case GradientFill::LINEAR:
+            // Linear gradient.
+            im.reset(new ImageRGBA(256, 1));
+
+            for (size_t i = 0; i < im->width(); i++) {
+
+                rgba sample = sampleGradient(gf, i);
+                im->setPixel(i, 0, sample.m_r, sample.m_g,
+                        sample.m_b, sample.m_a);
+            }
+            break;
+
+        case GradientFill::RADIAL:
+            // Focal gradient.
+            im.reset(new ImageRGBA(64, 64));
+
+            for (size_t j = 0; j < im->height(); j++)
+            {
+                for (size_t i = 0; i < im->width(); i++)
+                {
+                    float radiusy = (im->height() - 1) / 2.0f;
+                    float radiusx = radiusy + std::abs(radiusy * 
gf.focalPoint());
+                    float y = (j - radiusy) / radiusy;
+                    float x = (i - radiusx) / radiusx;
+                    int ratio = std::floor(255.5f * std::sqrt(x*x + y*y));
+                    
+                    if (ratio > 255) ratio = 255;
+
+                    rgba sample = sampleGradient(gf, ratio);
+                    im->setPixel(i, j, sample.m_r, sample.m_g,
+                            sample.m_b, sample.m_a);
+                }
+            }
+            break;
+        default:
+            break;
+    }
+
+    const BitmapInfo* bi = renderer.createBitmapInfo(
+                    static_cast<std::auto_ptr<GnashImage> >(im));
+
+    return bi;
+}
+
+} 
   
 } // namespace gnash
 
-
-/*
-
-Markus: A. A. I still miss you and the easter 2006, you know.
-  A. J. I miss you too, but you'll probably not read this code ever... :/
-
-*/
-

=== modified file 'testsuite/libcore.all/ClassSizes.cpp'
--- a/testsuite/libcore.all/ClassSizes.cpp      2010-07-29 06:24:31 +0000
+++ b/testsuite/libcore.all/ClassSizes.cpp      2010-07-31 14:05:26 +0000
@@ -35,7 +35,7 @@
 #include "Shape.h"
 #include "TextField.h"
 #include "SWFStream.h"
-#include "fill_style.h"
+#include "FillStyle.h"
 #include "swf/DefineFontAlignZonesTag.h"
 #include "swf/DefineShapeTag.h"
 #include "swf/DefineButtonCxformTag.h"
@@ -74,7 +74,7 @@
 (int) (float) (long) (double) \
 (Property*) (auto_ptr<Property>) (scoped_ptr<Property>) \
 (shared_ptr<Property>) (intrusive_ptr<as_object>) (GcResource) \
-(rgba) (SWFMatrix) (SWFRect) (LineStyle) (fill_style) (cxform) \
+(rgba) (SWFMatrix) (SWFRect) (LineStyle) (FillStyle) (cxform) \
 (as_value) \
 (DynamicShape)(ShapeRecord)(TextRecord) \
 (Property) (PropertyList) \

=== modified file 'testsuite/libcore.all/MatrixTest.cpp'
--- a/testsuite/libcore.all/MatrixTest.cpp      2010-03-12 23:37:40 +0000
+++ b/testsuite/libcore.all/MatrixTest.cpp      2010-08-02 07:54:02 +0000
@@ -79,7 +79,6 @@
     //  Test identity SWFMatrix.
     // 
     SWFMatrix identity; 
-    check(identity.is_valid());
     check_equals(identity.get_x_scale(), 1);
     check_equals(identity.get_y_scale(), 1);
     check_equals(identity.get_rotation(), 0);

=== modified file 'testsuite/misc-ming.all/DrawingApiTest.as'
--- a/testsuite/misc-ming.all/DrawingApiTest.as 2010-01-26 13:40:21 +0000
+++ b/testsuite/misc-ming.all/DrawingApiTest.as 2010-07-31 07:49:37 +0000
@@ -901,6 +901,70 @@
     beginGradientFill(fillType, colors, alphas, ratios, matrix);
     draw100x100Box(x, y, grad);
    
+
+    // Shape 14
+    x += 100;
+
+    // Test a linear gradient with one stop
+    fillType = "linear";
+    colors = [0xff0000];
+    alphas = [100];
+    ratios = [0];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+   
+
+    // Shape 15
+    x += 100;
+
+    // Test a linear gradient with one stop
+    fillType = "radial";
+    colors = [0x00ff00];
+    alphas = [100];
+    ratios = [0];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // Shape 16
+    x += 100;
+
+    // Bad fill style results in no fill.
+    fillType = "rodial";
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0x10, 0x05];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // Shape 17
+    x += 100;
+
+    // Extra arguments result in no fill for SWF6
+    fillType = "radial";
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0x10, 0x05];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad");
+    draw100x100Box(x, y, grad);
+
+    x = 0;
+    y += 100;
+
+    // Shape 18
+
+    // 4 arguments result in no fill for SWF6
+    fillType = "radial";
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0x10, 0x05];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios);
+    draw100x100Box(x, y, grad);
+
     _visible = false;
 
 };

=== modified file 'testsuite/misc-ming.all/DrawingApiTestRunner.cpp'
--- a/testsuite/misc-ming.all/DrawingApiTestRunner.cpp  2010-01-26 13:40:21 
+0000
+++ b/testsuite/misc-ming.all/DrawingApiTestRunner.cpp  2010-07-31 07:49:37 
+0000
@@ -22,8 +22,6 @@
 
 #include "MovieTester.h"
 #include "MovieClip.h"
-#include "DisplayObject.h"
-#include "DisplayList.h"
 #include "log.h"
 #include "GnashKey.h" // for gnash::key::code
 
@@ -1005,6 +1003,45 @@
     check_pixel(x + 90 - 2, y + 2, 2, green, 2);
     check_pixel(x + 90 - 2, y + 90 - 2, 2, green, 2);
 
+    // Shape 14
+    x += 100;
+    check_pixel(x + 7, y + 2, 2, red, 2);
+    check_pixel(x + 7, y + 90 - 2, 2, red, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, red, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, red, 2);
+
+    // Shape 15
+    x += 100;
+    check_pixel(x + 7, y + 2, 2, green, 2);
+    check_pixel(x + 7, y + 90 - 2, 2, green, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, green, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, green, 2);
+
+    // 3 invalid fills follow
+
+    // Shape 16
+    x += 100;
+    check_pixel(x + 7, y + 2, 2, white, 2);
+    check_pixel(x + 7, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+
+    // Shape 17
+    x += 100;
+    check_pixel(x + 7, y + 2, 2, white, 2);
+    check_pixel(x + 7, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+
+    x = 0;
+    y += 100;
+
+    // Shape 18
+    check_pixel(x + 7, y + 2, 2, white, 2);
+    check_pixel(x + 7, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+
     //----------------------------------------------------------
        // TODO: check startDrag/stopDrag on the hit detector
        // (hit 'd' key to toggle)

=== added file 'testsuite/misc-ming.all/GradientFillTest.as'
--- a/testsuite/misc-ming.all/GradientFillTest.as       1970-01-01 00:00:00 
+0000
+++ b/testsuite/misc-ming.all/GradientFillTest.as       2010-07-31 07:49:37 
+0000
@@ -0,0 +1,317 @@
+//
+// Some tests for the Drawing API
+// Build with:
+//     makeswf -o DrawingApi.swf DrawingApi.as
+// Run with:
+//     firefox DrawingApi.swf
+// Or:
+//     gnash DrawingApi.swf
+//
+//
+// Click the mouse button to turn the cursor shape into a mask and back.
+// Press a number on the keyboard to switch between "pages" of the drawing.
+// We currently have pages 1, 2, 3, 4.
+// All pages are tested automatically.
+//
+// '-' and '+' decrement and increment _alpha
+// 'h' toggles _visible
+//
+
+
+#include "../actionscript.all/check.as"
+ 
+// This tests the gradients found in DrawingApiTest for version 8, where
+// some extra arguments were added.
+
+// Make Matrix visible for easier gradient tests.
+ASSetPropFlags(_global, "flash", 0, 5248);
+
+draw100x100Box = function(x, y, mc) {
+    s = 90;
+    with (mc) {
+        moveTo(x, y);
+        lineTo(x + s, y);
+        lineTo(x + s, y + s);
+        lineTo(x, y + s);
+        lineTo(x, y);
+        endFill();
+    };
+};
+
+createEmptyMovieClip("grad", 150);
+
+// Test gradients.
+// The beginGradientFill function works with fake Matrices, but there is no
+// point making more work for ourselves as that testing is already done for
+// the Matrix class.
+// Only the "box" matrixType gets special handling.
+
+with(grad) {
+
+    // Linear gradients
+    fillType = "linear";
+
+    x = 0;
+    y = 0;
+
+    // shape 1
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix = new flash.geom.Matrix();
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 2
+    x += 100;
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 3
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 4
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 5
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4 * 3, x - 90, y - 90);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 6
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00, 0xff00ff, 0x00ffff, 0xffff00 ];
+    alphas = [100, 100, 100, 50, 25, 100];
+    ratios = [0, 0xff / 5, 0xff / 5 * 2, 0xff / 5 * 3, 0xff / 5 * 4, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 2, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+ 
+    // Radial gradients
+    fillType = "radial";
+
+    x = 0;
+    y += 100;
+
+    // shape 7
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix = new flash.geom.Matrix();
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 8
+    x += 100;
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 9
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 10
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 11
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4 * 3, x - 90, y - 90);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 12
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00, 0xff00ff, 0x00ffff, 0xffff00 ];
+    alphas = [100, 100, 100, 50, 25, 100];
+    ratios = [0, 0xff / 5, 0xff / 5 * 2, 0xff / 5 * 3, 0xff / 5 * 4, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 2, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    y += 100;
+    x = 0;
+
+    // Shape 13
+
+    // Check that ratios are adjusted if they do not get successively larger.
+    fillType = "linear";
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0x10, 0x05];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+   
+
+    // Shape 14
+    x += 100;
+
+    // Test a linear gradient with one stop
+    fillType = "linear";
+    colors = [0xff0000];
+    alphas = [100];
+    ratios = [0];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+   
+
+    // Shape 15
+    x += 100;
+
+    // Test a linear gradient with one stop
+    fillType = "radial";
+    colors = [0x00ff00];
+    alphas = [100];
+    ratios = [0];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // Shape 15
+    x += 100;
+
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad");
+    draw100x100Box(x, y, grad);
+    
+    // Shape 16
+    x += 100;
+
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "reflect");
+    draw100x100Box(x, y, grad);
+
+    // Shape 17
+    x += 100;
+
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "repeat");
+    draw100x100Box(x, y, grad);
+    
+    x = 0;
+    y += 100;
+    
+    // Shape 18
+
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "");
+    draw100x100Box(x, y, grad);
+    
+    // Shape 19
+    x += 100;
+
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad",
+            "RGB");
+    draw100x100Box(x, y, grad);
+
+
+    // Shape 20
+    x += 100;
+    
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad",
+            "linearRGB");
+    draw100x100Box(x, y, grad);
+
+    // Shape 21
+    x += 100;
+    
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad",
+            "");
+    draw100x100Box(x, y, grad);
+
+    // Shape 22
+    x += 100;
+    
+    // Test a radial gradient with SWF8 args
+    fillType = "radial";
+    colors = [0xffff00, 0x0000ff, 0x00ffff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xa0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix, "pad",
+            "RGB", 3.5);
+    draw100x100Box(x, y, grad);
+
+};
+grad.onRollOver = function() {};
+
+stop();
+
+

=== modified file 'testsuite/misc-ming.all/Makefile.am'
--- a/testsuite/misc-ming.all/Makefile.am       2010-07-29 06:24:31 +0000
+++ b/testsuite/misc-ming.all/Makefile.am       2010-07-31 07:49:37 +0000
@@ -37,6 +37,7 @@
        remoting.php \
        gotoFrame2Test.as \
        DrawingApiTest.as \
+       GradientFillTest.as \
        LC-Receive.as \
        LC-Send.as \
        FlashVarsTest.as \
@@ -2013,6 +2014,9 @@
                XMLSocketTest.swf > $@
        chmod 755 $@
 
+GradientFillTest.swf: $(srcdir)/GradientFillTest.as 
+       $(MAKESWF) -v 8 -r 1 -o $@  $(srcdir)/empty.as 
$(srcdir)/GradientFillTest.as
+
 DrawingApiTest.swf: $(srcdir)/DrawingApiTest.as 
        $(MAKESWF) -r 1 -o $@  $(srcdir)/empty.as $(srcdir)/DrawingApiTest.as
 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]