gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r12347: Implement beginBitmapFill wi


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r12347: Implement beginBitmapFill with all arguments:
Date: Wed, 04 Aug 2010 11:10:25 +0200
User-agent: Bazaar (2.0.3)

------------------------------------------------------------
revno: 12347 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Wed 2010-08-04 11:10:25 +0200
message:
  Implement beginBitmapFill with all arguments:
  
  1. User matrix
  2. Repeat (agg only, as the cairo renderer has never supported tiled bitmaps)
  3. Smoothing
  
  Rename BitmapInfo to CachedBitmap and provide functions to retrieve the
  CachedBitmap from the renderer when required.
  
  Implement BitmapData with an internal CachedBitmap (or GnashImage if no
  renderer is present) to allow a permanenent link with BitmapFills and
  reduce the image processing needed for attachBitmap.
  
  Add an argb_iterator to GnashImage to allow BitmapData to work fairly
  transparently with it. It's also useful for cairo.
renamed:
  libcore/BitmapInfo.h => libbase/CachedBitmap.h
modified:
  libbase/GnashImage.cpp
  libbase/GnashImage.h
  libbase/GnashImageJpeg.cpp
  libbase/GnashImageJpeg.h
  libbase/GnashVaapiImage.cpp
  libbase/GnashVaapiImage.h
  libbase/Makefile.am
  libcore/Bitmap.cpp
  libcore/Bitmap.h
  libcore/DisplayObject.h
  libcore/FillStyle.cpp
  libcore/FillStyle.h
  libcore/FreetypeGlyphsProvider.cpp
  libcore/Makefile.am
  libcore/MovieClip.h
  libcore/asobj/MovieClip_as.cpp
  libcore/asobj/flash/display/BitmapData_as.cpp
  libcore/asobj/flash/display/BitmapData_as.h
  libcore/parser/BitmapMovieDefinition.cpp
  libcore/parser/BitmapMovieDefinition.h
  libcore/parser/SWFMovieDefinition.cpp
  libcore/parser/SWFMovieDefinition.h
  libcore/parser/movie_definition.h
  libcore/parser/sprite_definition.h
  libcore/swf/tag_loaders.cpp
  libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
  libmedia/gst/VideoDecoderGst.h
  librender/Renderer.h
  librender/Renderer_agg.cpp
  librender/Renderer_agg_bitmap.h
  librender/Renderer_cairo.cpp
  librender/Renderer_cairo.h
  librender/Renderer_ogl.cpp
  librender/Renderer_ogl.h
  testsuite/MovieTester.cpp
  testsuite/misc-ming.all/BeginBitmapFill.c
  testsuite/misc-ming.all/BeginBitmapFillRunner.cpp
  libbase/CachedBitmap.h
=== renamed file 'libcore/BitmapInfo.h' => 'libbase/CachedBitmap.h'
--- a/libcore/BitmapInfo.h      2010-01-11 06:41:38 +0000
+++ b/libbase/CachedBitmap.h    2010-08-03 17:24:06 +0000
@@ -20,28 +20,46 @@
 #ifndef GNASH_BITMAP_INFO_H
 #define GNASH_BITMAP_INFO_H
 
-#include "ref_counted.h" // for inheritance
+#include "ref_counted.h"
 #include "dsodefs.h"
 
 namespace gnash {
 
-/// Your Renderer creates BitmapInfos for gnash.  You
-/// need to subclass BitmapInfo in order to add the
-/// information and functionality your app needs to render
-/// using textures.
-class DSOEXPORT BitmapInfo : public ref_counted
+class GnashImage;
+
+/// A CachedBitmap is created by the renderer in a format of its choosing.
+//
+/// CachedBitmaps are generally left alone by libcore, but the BitmapData
+/// API provides a way of manipulating bitmaps. For this reason an image()
+/// function is required, which must return a GnashImage for manipulation.
+class DSOEXPORT CachedBitmap : public ref_counted
 {
 public:
 
-       BitmapInfo() {}
-
-    virtual ~BitmapInfo() {}
+    CachedBitmap() {}
+
+    virtual ~CachedBitmap() {}
+
+    /// Return a GnashImage for manipulation.
+    //
+    /// The changes to the data must be cached before the next rendering.
+    virtual GnashImage& image() = 0;
+
+    /// Free the memory associated with this CachedBitmap.
+    //
+    /// This allows ActionScript a little bit of control over memory.
+    virtual void dispose() = 0;
+
+    /// Whether the CachedBitmap has been disposed.
+    //
+    /// A disposed CachedBitmap has no data and should not be rendered.
+    virtual bool disposed() const = 0;
+
 };
        
-
-}      // namespace gnash
-
-#endif // GNASH_BITMAP_INFO_H
+} // namespace gnash
+
+#endif
 
 
 // Local Variables:

=== modified file 'libbase/GnashImage.cpp'
--- a/libbase/GnashImage.cpp    2010-03-15 01:50:13 +0000
+++ b/libbase/GnashImage.cpp    2010-08-03 12:37:23 +0000
@@ -41,131 +41,95 @@
 {
 
 namespace {
-    void processAlpha(boost::uint8_t* imageData, size_t pixels);
+    void processAlpha(GnashImage::iterator imageData, size_t pixels);
 }
 
-//
-// GnashImage
-//
-
-/// Create an image taking ownership of the given buffer height*pitch bytes
-GnashImage::GnashImage(boost::uint8_t* data, int width,
-        int height, int pitch, ImageType type, ImageLocation location)
+GnashImage::GnashImage(iterator data, size_t width, size_t height,
+        ImageType type, ImageLocation location)
     :
     _type(type),
     _location(location),
-    _size(height*pitch),
     _width(width),
     _height(height),
-    _pitch(pitch),
     _data(data)
 {
 }
 
 /// Create an image allocating a buffer of height*pitch bytes
-GnashImage::GnashImage(int width, int height,
-        int pitch, ImageType type, ImageLocation location)
+GnashImage::GnashImage(size_t width, size_t height, ImageType type,
+        ImageLocation location)
     :
     _type(type),
     _location(location),
-    _size(height*pitch),
     _width(width),
-    _height(height),
-    _pitch(pitch),
-    _data(new boost::uint8_t[_size])
-{
-    assert(pitch >= width);
-}
-
-void GnashImage::update(const boost::uint8_t* data)
-{
-    std::memcpy(this->data(), data, _size);
-}
-
-void GnashImage::update(const GnashImage& from)
-{
-    assert(from._pitch == _pitch);
-    assert(_size <= from._size);
+    _height(height)
+{
+    const size_t max = std::numeric_limits<boost::int32_t>::max();
+    if (size() > max) {
+        throw std::bad_alloc();
+    }
+    _data.reset(new value_type[size()]);
+}
+
+void
+GnashImage::update(const_iterator data)
+{
+    std::copy(data, data + size(), _data.get());
+}
+
+void
+GnashImage::update(const GnashImage& from)
+{
+    assert(size() <= from.size());
+    assert(width() == from.width());
     assert(_type == from._type);
     assert(_location == from._location);
-    std::memcpy(data(), from.data(), _size);
-}
-
-boost::uint8_t* GnashImage::scanline(size_t y)
-{
-    assert(y < _height);
-    return data() + _pitch * y;
-}
-
-const boost::uint8_t* GnashImage::scanlinePointer(size_t y) const
-{
-    assert(y < _height);
-    return data() + _pitch * y;
-}
-
-
-//
-// ImageRGB
-//
-
-ImageRGB::ImageRGB(int width, int height)
+    std::memcpy(begin(), from.begin(), size());
+}
+
+ImageRGB::ImageRGB(size_t width, size_t height)
     :
-    GnashImage( width, height,
-        width * 3, GNASH_IMAGE_RGB)
+    GnashImage(width, height, GNASH_IMAGE_RGB)
 {
-    assert(width > 0);
-    assert(height > 0);
 }
 
 ImageRGB::~ImageRGB()
 {
 }
 
-
-//
-// ImageRGBA
-//
-
-
-ImageRGBA::ImageRGBA(int width, int height)
+ImageRGBA::ImageRGBA(size_t width, size_t height)
     :
-    GnashImage(width, height, width * 4, GNASH_IMAGE_RGBA)
+    GnashImage(width, height, GNASH_IMAGE_RGBA)
 {
-    assert(width > 0);
-    assert(height > 0);
-    assert(_pitch >= _width * 4);
-    assert((_pitch & 3) == 0);
 }
 
 ImageRGBA::~ImageRGBA()
 {
 }
 
-
 void
-ImageRGBA::setPixel(size_t x, size_t y, boost::uint8_t r, boost::uint8_t g,
-        boost::uint8_t b, boost::uint8_t a)
+ImageRGBA::setPixel(size_t x, size_t y, value_type r, value_type g,
+        value_type b, value_type a)
 {
     assert(x < _width);
     assert(y < _height);
 
-    boost::uint8_t* data = scanline(y) + 4 * x;
+    iterator data = scanline(*this, y) + 4 * x;
 
-    data[0] = r;
-    data[1] = g;
-    data[2] = b;
-    data[3] = a;
+    *data = r;
+    *(data + 1) = g;
+    *(data + 2) = b;
+    *(data + 3) = a;
 }
 
 
 void
-ImageRGBA::mergeAlpha(const boost::uint8_t* alphaData,
-        const size_t bufferLength)
+ImageRGBA::mergeAlpha(const_iterator alphaData, const size_t bufferLength)
 {
-    assert (bufferLength * 4 <= _size);
+    assert(bufferLength * 4 <= size());
 
     // Point to the first alpha byte
-    boost::uint8_t* p = data();
+    iterator p = begin();
 
     // Set each 4th byte to the correct alpha value and adjust the
     // other values.
@@ -196,30 +160,26 @@
             
     std::auto_ptr<ImageOutput> outChannel;
 
-    switch (type)
-    {
+    switch (type) {
 #ifdef USE_PNG
         case GNASH_FILETYPE_PNG:
-            outChannel = PngImageOutput::create(out, width,
-                    height, quality);
+            outChannel = PngImageOutput::create(out, width, height, quality);
             break;
 #endif
         case GNASH_FILETYPE_JPEG:
-            outChannel = JpegImageOutput::create(out, width,
-                    height, quality);
+            outChannel = JpegImageOutput::create(out, width, height, quality);
             break;
         default:
             log_error("Requested to write image as unsupported filetype");
             break;
     }
 
-    switch (image.type())
-    {
+    switch (image.type()) {
         case GNASH_IMAGE_RGB:
-            outChannel->writeImageRGB(image.data());
+            outChannel->writeImageRGB(image.begin());
             break;
         case GNASH_IMAGE_RGBA:
-            outChannel->writeImageRGBA(image.data());
+            outChannel->writeImageRGBA(image.begin());
             break;
         default:
             break;
@@ -231,11 +191,10 @@
 std::auto_ptr<GnashImage>
 ImageInput::readImageData(boost::shared_ptr<IOChannel> in, FileType type)
 {
-    std::auto_ptr<GnashImage> im (NULL);
+    std::auto_ptr<GnashImage> im;
     std::auto_ptr<ImageInput> inChannel;
 
-    switch (type)
-    {
+    switch (type) {
 #ifdef USE_PNG
         case GNASH_FILETYPE_PNG:
             inChannel = PngImageInput::create(in);
@@ -258,10 +217,8 @@
     const size_t height = inChannel->getHeight();
     const size_t width = inChannel->getWidth();
 
-    try
-    {
-        switch (inChannel->imageType())
-        {
+    try {
+        switch (inChannel->imageType()) {
             case GNASH_IMAGE_RGB:
                 im.reset(new ImageRGB(width, height));
                 break;
@@ -273,8 +230,7 @@
                 return im;
         }
     }
-    catch (std::bad_alloc& e)
-    {
+    catch (std::bad_alloc& e) {
         // This should be caught here because ~JpegImageInput can also
         // throw an exception on stack unwinding and this confuses
         // remote catchers.
@@ -283,8 +239,9 @@
         return im;
     }
     
+
     for (size_t i = 0; i < height; ++i) {
-        inChannel->readScanline(im->scanline(i));
+        inChannel->readScanline(scanline(*im, i));
     }
 
     // The renderers expect RGBA data to be preprocessed. JPEG images are
@@ -292,7 +249,7 @@
     // in the SWF is possible; in that case, the processing happens during
     // mergeAlpha().
     if (im->type() == GNASH_IMAGE_RGBA) {
-        processAlpha(im->data(), width * height);
+        processAlpha(im->begin(), width * height);
     }
     return im;
 }
@@ -319,15 +276,14 @@
 
     im.reset(new ImageRGBA(width, height));
 
-    boost::scoped_array<boost::uint8_t> line(new boost::uint8_t[3 * width]);
+    boost::scoped_array<GnashImage::value_type> line(
+            new GnashImage::value_type[3 * width]);
 
-    for (size_t y = 0; y < height; ++y) 
-    {
+    for (size_t y = 0; y < height; ++y) {
         j_in->readScanline(line.get());
 
-        boost::uint8_t* data = im->scanline(y);
-        for (size_t x = 0; x < width; ++x) 
-        {
+        GnashImage::iterator data = scanline(*im, y);
+        for (size_t x = 0; x < width; ++x) {
             data[4*x+0] = line[3*x+0];
             data[4*x+1] = line[3*x+1];
             data[4*x+2] = line[3*x+2];
@@ -341,12 +297,11 @@
 namespace {
 
 void
-processAlpha(boost::uint8_t* imageData, size_t pixels)
+processAlpha(GnashImage::iterator imageData, size_t pixels)
 {
-
-    boost::uint8_t* p = imageData;
+    GnashImage::iterator p = imageData;
     for (size_t i = 0; i < pixels; ++i) {
-        boost::uint8_t alpha = *(p + 3);
+        GnashImage::value_type alpha = *(p + 3);
         *p = std::min(*p, alpha);
         ++p;
         *p = std::min(*p, alpha);

=== modified file 'libbase/GnashImage.h'
--- a/libbase/GnashImage.h      2010-07-03 11:38:59 +0000
+++ b/libbase/GnashImage.h      2010-08-04 06:59:22 +0000
@@ -28,21 +28,21 @@
 #include <boost/noncopyable.hpp>
 #include <boost/cstdint.hpp>
 #include <boost/scoped_array.hpp>
-#include <memory> // for auto_ptr
+#include <memory> 
+#include <boost/iterator/iterator_facade.hpp>
+#include <iterator>
 
 #include "FileTypes.h"
 #include "log.h"
 #include "dsodefs.h"
 
-
 // Forward declarations
 namespace gnash {
     class IOChannel;
     class JpegImageInput;
 }
 
-namespace gnash
-{
+namespace gnash {
 
 /// The types of images handled in Gnash.
 enum ImageType
@@ -59,212 +59,297 @@
     GNASH_IMAGE_GPU
 };
 
+inline size_t
+numChannels(ImageType t)
+{
+    switch (t) {
+        case GNASH_IMAGE_RGBA:
+            return 4;
+        case GNASH_IMAGE_RGB:
+            return 3;
+        default:
+            std::abort();
+    }
+}
+
+template<typename Iterator>
+class ARGB
+{
+public:
+
+    ARGB(Iterator i, ImageType t)
+        :
+        _it(i),
+        _t(t)
+    {}
+    
+    /// Writes a 32-bit unsigned value in ARGB byte order to the image
+    //
+    /// Take note of the different byte order!
+    ARGB& operator=(boost::uint32_t pixel) {
+        switch (_t) {
+            case GNASH_IMAGE_RGBA:
+                // alpha
+                *(_it + 3) = (pixel & 0xff000000) >> 24;
+            case GNASH_IMAGE_RGB:
+                *_it = (pixel & 0x00ff0000) >> 16;
+                *(_it + 1) = (pixel & 0x0000ff00) >> 8;
+                *(_it + 2) = (pixel & 0x000000ff);
+            default:
+                break;
+        }
+        return *this;
+    }
+
+private:
+    Iterator _it;
+    ImageType _t;
+};
+
+template<typename Iterator, typename Pixel>
+struct pixel_iterator : public boost::iterator_facade<
+                            pixel_iterator<Iterator, Pixel>,
+                            boost::uint32_t,
+                            std::random_access_iterator_tag,
+                            Pixel>
+{
+
+    typedef std::ptrdiff_t difference_type;
+
+    pixel_iterator(Iterator it, ImageType t)
+        :
+        _it(it),
+        _t(t)
+    {}
+ 
+    boost::uint32_t toARGB() const {
+        boost::uint32_t ret = 0xff000000;
+        switch (_t) {
+            case GNASH_IMAGE_RGBA:
+                // alpha
+                ret = *(_it + 3) << 24;
+            case GNASH_IMAGE_RGB:
+                ret |= (*_it << 16 | *(_it + 1) << 8 | *(_it + 2));
+            default:
+                break;
+        }
+        return ret;
+    }
+
+private:
+
+    friend class boost::iterator_core_access;
+
+    Pixel dereference() const {
+        return Pixel(_it, _t);
+    }
+
+    void increment() {
+        _it += numChannels(_t);
+    }
+
+    bool equal(const pixel_iterator& o) const {
+        return o._it == _it;
+    }
+
+    difference_type distance_to(const pixel_iterator& o) const {
+        return (o._it - _it) / numChannels(_t);
+    }
+
+    void advance(difference_type n) {
+        _it += n * numChannels(_t);
+    }
+
+    Iterator _it;
+    ImageType _t;
+};
 
 /// Base class for different types of bitmaps
 //
-/// @todo document layout of the image, like pixel data
-///       order in the raw array (rows or columns first?)
-///
-class DSOEXPORT GnashImage
+/// 1. Bytes are packed in RGB(A) order.
+/// 2. Rowstride is equal to channels * width
+class DSOEXPORT GnashImage : boost::noncopyable
 {
 public:
 
-    /// Copy an GnashImage.
-    GnashImage(const GnashImage& o) throw (std::bad_alloc)
-        :
-        _type(o._type),
-        _location(o._location),
-        _size(o.size()),
-        _width(o.width()),
-        _height(o.height()),
-        _pitch(o._pitch),
-        _data(new boost::uint8_t[_size])
-    {
-        update(o);
-    }
-    
-    /// \brief Construct an GnashImage from a data buffer,
-    /// taking ownership of the data.
-    //
-    /// @param data     The raw image data. This class takes ownership.
-    /// @param width    The width of the image in pixels.
-    /// @param height   The height of the image in pixels.
-    /// @param pitch    The pitch (rowstride) of the image in bytes.
-    /// @param type     The ImageType of the image.
-    GnashImage(boost::uint8_t *data, int width, int height,
-               int pitch, ImageType type,
-               ImageLocation location = GNASH_IMAGE_CPU);
-
-    /// Construct an empty GnashImage
-    //
-    /// Once constructed, this image must be updated with update() before
-    /// use.
-    //
-    /// @param width    The width of the image in pixels.
-    /// @param height   The height of the image in pixels.
-    /// @param pitch    The pitch (rowstride) of the image in bytes.
-    /// @param type     The ImageType of the image.
-    GnashImage(int width, int height, int pitch, ImageType type,
-               ImageLocation location = GNASH_IMAGE_CPU);
+    typedef boost::uint8_t value_type;
+    typedef boost::scoped_array<value_type> container_type;
+    typedef value_type* iterator;
+    typedef const value_type* const_iterator;
+
+    typedef pixel_iterator<iterator, ARGB<iterator> > argb_iterator;
+
+    virtual ~GnashImage() {}
 
     /// Return the ImageType of the image.
     //
     /// This saves guessing when dynamic_cast is used.
-    ImageType type() const { return _type; }
+    ImageType type() const {
+        return _type;
+    }
 
     /// Return the ImageLocation of the image.
     //
     /// This saves guessing when dynamic_cast is used.
-    ImageLocation location() const { return _location; }
+    ImageLocation location() const {
+        return _location;
+    }
 
     /// Get the size of the image buffer
     //
     /// @return     The size of the buffer in bytes
-    size_t size() const { return _size; }
+    size_t size() const {
+        return stride() * _height;
+    }
 
     /// Get the pitch of the image buffer
     //
-    /// @return     The pitch of the buffer in bytes
-    size_t pitch() const { return _pitch; }
+    /// @return     The rowstride of the buffer in bytes
+    virtual size_t stride() const {
+        return _width * channels();
+    }
 
-    /// Get size of a single pixel
+    /// Get the number of channels
     //
-    /// @return     The size of a single pixel in bytes.
-    size_t pixelSize() const
-    {
-        return _pitch / _width;
+    /// @return     The number of channels
+    size_t channels() const {
+        return numChannels(_type);
     }
 
     /// Get the image's width
     //
     /// @return     The image's width in pixels.
-    size_t width() const { return _width; }
+    size_t width() const {
+        return _width;
+    }
 
     /// Get the image's width
     //
     /// @return     The image's height in pixels.
-    size_t height() const { return _height; }
+    size_t height() const {
+        return _height;
+    }
 
     /// Copy image data from a buffer.
     //
-    /// Note that this buffer MUST have the same _pitch, or unexpected things
-    /// will happen. In general, it is only safe to copy from another 
GnashImage
-    /// (or derivative thereof) or unexpected things will happen. 
-    ///
-    /// @param data buffer to copy data from.
-    ///
-    void update(const boost::uint8_t* data);
+    /// Note that this buffer MUST have the same rowstride and type, or
+    /// unexpected things will happen. In general, it is only safe to copy
+    /// from another GnashImage or unexpected things will happen. 
+    ///
+    /// @param data     buffer to copy data from.
+    void update(const_iterator data);
 
     /// Copy image data from another image data
     //
-    /// Note that this buffer MUST have the same _pitch and _type
-    /// or an assertion will fail.
-    ///
-    /// @param from image to copy data from.
-    ///
+    /// Note that this buffer must have the same rowstride and type
+    ///
+    /// @param from     image to copy data from.
     void update(const GnashImage& from);
     
-    /// Get access to the underlying data
-    //
-    /// @return     A pointer to the raw image data.
-    virtual boost::uint8_t* data() { return _data.get(); }
-
-    /// Get read-only access to the underlying data
-    //
-    /// @return     A read-only pointer to the raw image data.
-    virtual const boost::uint8_t* data() const { return _data.get(); }
-
-    /// Get a pointer to a given row
-    //
-    /// @param y    The index of the required row.
-    /// @return     A pointer to the first byte of the specified row.
-    boost::uint8_t* scanline(size_t y);
-
-    /// Get a read-only pointer to a given row
-    //
-    /// @param y    The index of the required row.
-    /// @return     A read-only pointer to the first byte of the specified
-    ///             row.
-    DSOEXPORT const boost::uint8_t* scanlinePointer(size_t y) const;
-
-    virtual ~GnashImage() {}
-
-    /// Clone the GnashImage.
-    //
-    /// @return     A copy of the GnashImage, owned by the caller.
-    virtual std::auto_ptr<GnashImage> clone() = 0;
+    /// Access the raw data.
+    virtual iterator begin() {
+        return _data.get();
+    }
+
+    /// Access the raw data
+    virtual const_iterator begin() const {
+        return _data.get();
+    }
+
+    /// An iterator to the end of the data.
+    iterator end() {
+        return begin() + size();
+    }
+
+    /// An iterator to the end of the data.
+    const_iterator end() const {
+        return begin() + size();
+    }
+
+    /// An iterator to write data in ARGB format to the bitmap
+    argb_iterator argb_begin() {
+        return argb_iterator(begin(), _type);
+    }
+    
+    /// An argb_iterator to the end of the data.
+    argb_iterator argb_end() {
+        return argb_iterator(end(), _type);
+    }
 
 protected:
 
+    /// Construct a GnashImage from a data buffer, taking ownership of the 
data.
+    //
+    /// @param data     The raw image data. This class takes ownership.
+    /// @param width    The width of the image in pixels.
+    /// @param height   The height of the image in pixels.
+    /// @param pitch    The pitch (rowstride) of the image in bytes.
+    /// @param type     The ImageType of the image.
+    GnashImage(iterator data, size_t width, size_t height, ImageType type,
+            ImageLocation location = GNASH_IMAGE_CPU);
+
+    /// Construct an empty GnashImage
+    //
+    /// Note: there is an arbitrary limit of boost::int32_t::max bytes for the
+    /// total size of the bitmap constructed with this constructor.
+    //
+    /// @param width    The width of the image in pixels.
+    /// @param height   The height of the image in pixels.
+    /// @param type     The ImageType of the image.
+    GnashImage(size_t width, size_t height, ImageType type,
+               ImageLocation location = GNASH_IMAGE_CPU);
+
+
+    /// The type of the image: RGBA or RGB.
     const ImageType _type;
 
     /// Image data location (CPU or GPU)
     const ImageLocation _location;
 
-    /// Size of image buffer in bytes.
-    const size_t _size;
-
     /// Width of image, in pixels
     const size_t _width;
 
     /// Height of image, in pixels
     const size_t _height;
 
-    /// Byte offset from one row to the next
-    //
-    /// This is basically width in bytes of each line.
-    /// For example, in an alpha image type this is equal to _width
-    /// while for an RGB this is 3 times the _width.
-    const size_t _pitch;
-
-    /// Data bytes, geometry defined by members below
-    boost::scoped_array<boost::uint8_t> _data;
+    /// Data if held in this class
+    container_type _data;
 
 };
 
-/// 24-bit RGB image.  Packed data, red byte first (RGBRGB...)
+/// 24-bit RGB bitmap
+//
+/// Channels are in RGB order.
 class DSOEXPORT ImageRGB : public GnashImage
 {
-
 public:
 
-    ImageRGB(int width, int height);
-
-    ImageRGB(const ImageRGB& o)
-        :
-        GnashImage(o)
-    {}
-
-    ImageRGB(boost::uint8_t* data, int width, int height, int stride)
-        :
-        GnashImage(data, width, height, stride, GNASH_IMAGE_RGB)
-    {}
-
-    ~ImageRGB();
-
-    virtual std::auto_ptr<GnashImage> clone()
-    {
-        return std::auto_ptr<GnashImage>(new ImageRGB(*this));
-    };
-
+    /// Create an empty RGB image with uninitialized data.
+    ImageRGB(size_t width, size_t height);
+
+    /// Create an ImageRGB taking ownership of the data.
+    ImageRGB(iterator data, size_t width, size_t height)
+        :
+        GnashImage(data, width, height, GNASH_IMAGE_RGB)
+    {}
+
+    virtual ~ImageRGB();
 };
 
-/// 32-bit RGBA image.  Packed data, red byte first (RGBARGBA...)
+/// 32-bit RGBA bitmap
+//
+/// Channels are in RGBA order.
 class DSOEXPORT ImageRGBA : public GnashImage
 {
 
 public:
 
-    ImageRGBA(int width, int height);
-
-    ImageRGBA(const ImageRGBA& o)
-        :
-        GnashImage(o)
-    {}
-
-    ImageRGBA(boost::uint8_t* data, int width, int height, int stride)
-        :
-        GnashImage(data, width, height, stride, GNASH_IMAGE_RGBA)
+    /// Create an empty RGB image with uninitialized data.
+    ImageRGBA(size_t width, size_t height);
+
+    ImageRGBA(iterator data, size_t width, size_t height)
+        :
+        GnashImage(data, width, height, GNASH_IMAGE_RGBA)
     {}
     
     ~ImageRGBA();
@@ -273,21 +358,16 @@
     //
     /// TODO: move in base class ?
     ///
-    void setPixel(size_t x, size_t y, boost::uint8_t r, boost::uint8_t g, 
boost::uint8_t b, boost::uint8_t a);
-
-    void mergeAlpha(const boost::uint8_t* alphaData, const size_t 
bufferLength);
-
-    virtual std::auto_ptr<GnashImage> clone()
-    {
-        return std::auto_ptr<GnashImage>(new ImageRGBA(*this));
-    };
+    void setPixel(size_t x, size_t y, value_type r, value_type g, value_type b,
+            value_type a);
+
+    void mergeAlpha(const_iterator alphaData, const size_t bufferLength);
 
 };
 
 /// The base class for reading image data. 
 class ImageInput : boost::noncopyable
 {
-
 public:
 
     /// Construct an ImageInput object to read from an IOChannel.
@@ -295,7 +375,8 @@
     /// @param in   The stream to read data from. Ownership is shared
     ///             between caller and ImageInput, so it is freed
     ///             automatically when the last owner is destroyed.
-    ImageInput(boost::shared_ptr<IOChannel> in) :
+    ImageInput(boost::shared_ptr<IOChannel> in)
+        :
         _inStream(in),
         _type(GNASH_IMAGE_INVALID)
     {}
@@ -368,11 +449,12 @@
     ///                 is shared.
     /// @param width    The width of the resulting image
     /// @param height   The height of the resulting image.
-    ImageOutput(boost::shared_ptr<IOChannel> out, size_t width, size_t height) 
:
+    ImageOutput(boost::shared_ptr<IOChannel> out, size_t width, size_t height)
+        :
         _width(width),
         _height(height),
         _outStream(out)
-        {}
+    {}
 
     virtual ~ImageOutput() {}
     
@@ -400,7 +482,6 @@
             boost::shared_ptr<gnash::IOChannel> out, const GnashImage& image,
             int quality);
 
-
 protected:
 
     const size_t _width;
@@ -411,8 +492,28 @@
 
 };
 
+/// Get a pointer to a given row of any image.
+//
+/// @param row    The index of the required row.
+/// @return     A pointer to the first byte of the specified row.
+inline GnashImage::iterator
+scanline(GnashImage& im, size_t row)
+{
+    assert(row < im.height());
+    return im.begin() + im.stride() * row;
+}
+
+/// Get a read-only pointer to a given row of any image.
+//
+/// @param y    The index of the required row.
+/// @return     A read-only pointer to the first byte of the specified row.
+inline GnashImage::const_iterator
+scanline(const GnashImage& im, size_t row)
+{
+    assert(row < im.height());
+    return im.begin() + im.stride() * row;
+}
+
 } // namespace gnash
 
-
-
 #endif

=== modified file 'libbase/GnashImageJpeg.cpp'
--- a/libbase/GnashImageJpeg.cpp        2010-06-10 06:28:49 +0000
+++ b/libbase/GnashImageJpeg.cpp        2010-08-03 12:37:23 +0000
@@ -73,7 +73,6 @@
     
     in->errorOccurred(cinfo->err->jpeg_message_table[cinfo->err->msg_code]); 
 
-    //log_error("failing to abort jpeg parser here (would need a long-jump 
call)");
 }
 
 
@@ -255,7 +254,9 @@
 {
     finishImage();
 
-    rw_source_IOChannel* src = 
reinterpret_cast<rw_source_IOChannel*>(m_cinfo.src);
+    rw_source_IOChannel* src =
+        reinterpret_cast<rw_source_IOChannel*>(m_cinfo.src);
+
     delete src;
     m_cinfo.src = NULL;
 
@@ -279,26 +280,27 @@
 void
 JpegImageInput::readHeader(unsigned int maxHeaderBytes)
 {
-    if ( setjmp(_jmpBuf) )
-    {
+    if (setjmp(_jmpBuf)) {
         std::stringstream ss;
         ss << _("Internal jpeg error: ") << _errorOccurred;
         throw ParserException(ss.str());
     }
 
-    if ( maxHeaderBytes )
-    {
+    if (maxHeaderBytes) {
         // Read the encoding tables.
         // TODO: how to limit reads ?
         int ret = jpeg_read_header(&m_cinfo, FALSE);
-        switch (ret)
-        {
-            case JPEG_SUSPENDED: // suspended due to lack of data
-                throw ParserException(_("Lack of data during JPEG header 
parsing"));
-                break;
-            case JPEG_HEADER_OK: // Found valid image datastream
-                break;
-            case JPEG_HEADER_TABLES_ONLY: // Found valid table-specs-only 
datastream
+        switch (ret) {
+            case JPEG_SUSPENDED: 
+                // suspended due to lack of data
+                throw ParserException(_("Lack of data during JPEG "
+                            "header parsing"));
+                break;
+            case JPEG_HEADER_OK: 
+                // Found valid image datastream
+                break;
+            case JPEG_HEADER_TABLES_ONLY:
+                // Found valid table-specs-only datastream
                 break;
             default:
                 log_debug(_("unexpected: jpeg_read_header returned %d 
[%s:%d]"),
@@ -306,8 +308,7 @@
                 break;
         }
 
-        if (_errorOccurred)
-        {
+        if (_errorOccurred) {
             std::stringstream ss;
             ss << _("Internal jpeg error: ") << _errorOccurred;
             throw ParserException(ss.str());
@@ -325,27 +326,27 @@
 {
     assert(!_compressorOpened);
 
-    if ( setjmp(_jmpBuf) )
-    {
+    if (setjmp(_jmpBuf)) {
         std::stringstream ss;
         ss << _("Internal jpeg error: ") << _errorOccurred;
         throw ParserException(ss.str());
     }
 
-
     // hack, FIXME
     static const int stateReady = 202;    /* found SOS, ready for 
start_decompress */
-    while (m_cinfo.global_state != stateReady)
-    {
+    while (m_cinfo.global_state != stateReady) {
         int ret = jpeg_read_header(&m_cinfo, FALSE);
-        switch (ret)
-        {
-            case JPEG_SUSPENDED: // suspended due to lack of data
-                throw ParserException(_("lack of data during JPEG header 
parsing"));
-                break;
-            case JPEG_HEADER_OK: // Found valid image datastream
-                break;
-            case JPEG_HEADER_TABLES_ONLY: // Found valid table-specs-only 
datastream
+        switch (ret) {
+            case JPEG_SUSPENDED: 
+                // suspended due to lack of data
+                throw ParserException(_("lack of data during JPEG "
+                            "header parsing"));
+                break;
+            case JPEG_HEADER_OK: 
+                // Found valid image datastream
+                break;
+            case JPEG_HEADER_TABLES_ONLY: 
+                // Found valid table-specs-only datastream
                 break;
             default:
                 log_debug(_("unexpected: jpeg_read_header returned %d 
[%s:%d]"),
@@ -354,8 +355,7 @@
         }
     }
 
-    if (_errorOccurred)
-    {
+    if (_errorOccurred) {
         std::stringstream ss;
         ss << _("Internal jpeg error during header parsing: ") << 
_errorOccurred;
         throw ParserException(ss.str());
@@ -363,8 +363,7 @@
 
     jpeg_start_decompress(&m_cinfo);
 
-    if (_errorOccurred)
-    {
+    if (_errorOccurred) {
         std::stringstream ss;
         ss << _("Internal jpeg error during decompression: ") << 
_errorOccurred;
         throw ParserException(ss.str());
@@ -382,15 +381,13 @@
 void
 JpegImageInput::finishImage()
 {
-    if ( setjmp(_jmpBuf) )
-    {
+    if (setjmp(_jmpBuf)) {
         std::stringstream ss;
         ss << _("Internal jpeg error: ") << _errorOccurred;
         throw ParserException(ss.str());
     }
 
-    if (_compressorOpened)
-    {
+    if (_compressorOpened) {
         jpeg_finish_decompress(&m_cinfo);
         _compressorOpened = false;
     }
@@ -427,19 +424,17 @@
 JpegImageInput::readScanline(unsigned char* rgb_data)
 {
     assert(_compressorOpened);
-
     assert(m_cinfo.output_scanline < m_cinfo.output_height);
-    int    lines_read = jpeg_read_scanlines(&m_cinfo, &rgb_data, 1);
+
+    const int lines_read = jpeg_read_scanlines(&m_cinfo, &rgb_data, 1);
     assert(lines_read == 1);
-    lines_read = lines_read;    // avoid warning in NDEBUG
+
     // Expand grayscale to RGB
-    if (m_cinfo.out_color_space == JCS_GRAYSCALE)
-    {
+    if (m_cinfo.out_color_space == JCS_GRAYSCALE) {
         size_t w = getWidth();
         unsigned char* src = rgb_data + w - 1;
         unsigned char* dst = rgb_data + (w * 3) - 1;
-        for (;  w;  w--, src--)
-        {
+        for (;  w;  w--, src--) {
             *dst-- = *src;
             *dst-- = *src;
             *dst-- = *src;
@@ -461,11 +456,11 @@
     std::longjmp(_jmpBuf, 1);
 }
 
-std::auto_ptr<GnashImage>
-JpegImageInput::readSWFJpeg2WithTables(JpegImageInput& loader)
 // Create and read a new image, using a input object that
 // already has tables loaded.  The IJG documentation describes
 // this as "abbreviated" format.
+std::auto_ptr<GnashImage>
+JpegImageInput::readSWFJpeg2WithTables(JpegImageInput& loader)
 {
 
     loader.read();
@@ -474,7 +469,7 @@
             new ImageRGB(loader.getWidth(), loader.getHeight()));
 
     for (size_t y = 0, height = loader.getHeight(); y < height; y++) {
-        loader.readScanline(im->scanline(y));
+        loader.readScanline(scanline(*im, y));
     }
 
     loader.finishImage();
@@ -627,9 +622,11 @@
 
 
 std::auto_ptr<ImageOutput>
-JpegImageOutput::create(boost::shared_ptr<IOChannel> out, size_t width, size_t 
height, int quality)
+JpegImageOutput::create(boost::shared_ptr<IOChannel> out, size_t width,
+        size_t height, int quality)
 {
-    std::auto_ptr<ImageOutput> outChannel(new JpegImageOutput(out, width, 
height, quality));
+    std::auto_ptr<ImageOutput> outChannel(
+            new JpegImageOutput(out, width, height, quality));
     return outChannel;
 }
 

=== modified file 'libbase/GnashImageJpeg.h'
--- a/libbase/GnashImageJpeg.h  2010-01-25 18:52:20 +0000
+++ b/libbase/GnashImageJpeg.h  2010-08-03 09:30:37 +0000
@@ -125,9 +125,9 @@
     /// @param in   The IOChannel to read JPEG data from.
     static std::auto_ptr<ImageInput> create(boost::shared_ptr<IOChannel> in)
     {
-        std::auto_ptr<ImageInput> ret ( new JpegImageInput(in) );
+        std::auto_ptr<ImageInput> ret(new JpegImageInput(in));
         // might throw an exception (I guess)
-        if ( ret.get() ) ret->read();
+        if (ret.get()) ret->read();
         return ret;
     }
 
@@ -150,9 +150,9 @@
     static std::auto_ptr<JpegImageInput> createSWFJpeg2HeaderOnly(
             boost::shared_ptr<IOChannel> in, unsigned int maxHeaderBytes)
     {
-        std::auto_ptr<JpegImageInput> ret ( new JpegImageInput(in) );
+        std::auto_ptr<JpegImageInput> ret (new JpegImageInput(in));
         // might throw an exception
-        if ( ret.get() ) ret->readHeader(maxHeaderBytes);
+        if (ret.get()) ret->readHeader(maxHeaderBytes);
         return ret;
     }
 

=== modified file 'libbase/GnashVaapiImage.cpp'
--- a/libbase/GnashVaapiImage.cpp       2010-03-02 23:26:48 +0000
+++ b/libbase/GnashVaapiImage.cpp       2010-08-04 06:59:22 +0000
@@ -39,29 +39,9 @@
 #endif
 }
 
-/// Get scanline pitch for the specified image type
-static inline int get_pitch(int width, ImageType type)
-{
-    int bytes_per_pixel;
-
-    switch (type) {
-    case GNASH_IMAGE_RGB:
-        bytes_per_pixel = 3;
-        break;
-    case GNASH_IMAGE_RGBA:
-        bytes_per_pixel = 4;
-        break;
-    default:
-        assert(0);
-        bytes_per_pixel = 0;
-        break;
-    }
-    return width * bytes_per_pixel;
-}
-
 GnashVaapiImage::GnashVaapiImage(boost::shared_ptr<VaapiSurface> surface, 
ImageType type)
-    : GnashImage(NULL, surface->width(), surface->height(), 
get_pitch(surface->width(), type),
-                 type, GNASH_IMAGE_GPU)
+    : GnashImage(NULL, surface->width(), surface->height(), type,
+            GNASH_IMAGE_GPU)
     , _surface(surface)
     , _creation_time(get_ticks_usec())
 {
@@ -69,30 +49,12 @@
           _surface->get(), _width, _height);
 }
 
-GnashVaapiImage::GnashVaapiImage(const GnashVaapiImage& o)
-    : GnashImage(NULL, o.width(), o.height(), get_pitch(o.width(), o.type()),
-                 o.type(), GNASH_IMAGE_GPU)
-    , _surface(o.surface())
-    , _creation_time(get_ticks_usec())
-{
-    log_debug("GnashVaapiImage::GnashVaapiImage(): VA image %p\n", &o);
-
-    update(o);
-}
-
 GnashVaapiImage::~GnashVaapiImage()
 {
     log_debug("GnashVaapiImage::~GnashVaapiImage(): surface 0x%08x\n",
           _surface->get());
 }
 
-std::auto_ptr<GnashImage> GnashVaapiImage::clone()
-{
-    log_debug("GnashVaapiImage::clone(): image %p\n", this);
-
-    return std::auto_ptr<GnashImage>(new GnashVaapiImage(*this));
-}
-
 void GnashVaapiImage::update(boost::shared_ptr<VaapiSurface> surface)
 {
     _surface = surface;
@@ -109,13 +71,13 @@
 
 void GnashVaapiImage::update(const GnashImage& from)
 {
-    assert(_pitch == from.pitch());
-    assert(_size <= from.size());
-    assert(_type == from.type());
+    assert(stride() == from.stride());
+    assert(size() <= from.size());
+    assert(type() == from.type());
 
     switch (from.location()) {
     case GNASH_IMAGE_CPU:
-        this->update(const_cast<boost::uint8_t *>(from.data()));
+        this->update(const_cast<boost::uint8_t *>(from.begin()));
         break;
     case GNASH_IMAGE_GPU:
         this->update(static_cast<const GnashVaapiImage &>(from).surface());
@@ -141,7 +103,8 @@
 }
 
 // Get access to the underlying data
-boost::uint8_t* GnashVaapiImage::data()
+GnashImage::iterator
+GnashVaapiImage::begin()
 {
     log_debug("GnashVaapiImage::data(): surface 0x%08x\n", _surface->get());
     log_debug("  -> %u usec from creation\n",
@@ -155,7 +118,8 @@
 }
 
 // Get read-only access to the underlying data
-const boost::uint8_t* GnashVaapiImage::data() const
+GnashImage::const_iterator
+GnashVaapiImage::begin() const
 {
     log_debug("GnashVaapiImage::data() const: surface 0x%08x\n", 
_surface->get());
     log_debug("  -> %u usec from creation\n",

=== modified file 'libbase/GnashVaapiImage.h'
--- a/libbase/GnashVaapiImage.h 2010-02-28 19:20:31 +0000
+++ b/libbase/GnashVaapiImage.h 2010-08-04 06:59:22 +0000
@@ -43,7 +43,6 @@
     GnashVaapiImage(const GnashVaapiImage& o);
     ~GnashVaapiImage();
 
-    virtual std::auto_ptr<GnashImage> clone();
     virtual void update(boost::shared_ptr<VaapiSurface> surface);
     virtual void update(boost::uint8_t* data);
     virtual void update(const GnashImage& from);
@@ -59,12 +58,12 @@
     /// NOTE: This function shall not be used
     //
     /// @return     NULL.
-    virtual boost::uint8_t* data();
+    virtual iterator begin();
 
     /// Get read-only access to the underlying data
     //
     /// @return     A read-only pointer to the raw image data.
-    virtual const boost::uint8_t* data() const;
+    virtual const_iterator begin() const;
 };
 
 } // gnash namespace

=== modified file 'libbase/Makefile.am'
--- a/libbase/Makefile.am       2010-07-14 16:00:04 +0000
+++ b/libbase/Makefile.am       2010-08-03 16:40:04 +0000
@@ -213,6 +213,7 @@
        NetworkAdapter.h \
        NamingPolicy.h \
        GnashImageJpeg.h \
+       CachedBitmap.h \
        GnashImage.h \
        $(NULL)
 

=== modified file 'libcore/Bitmap.cpp'
--- a/libcore/Bitmap.cpp        2010-07-31 14:22:03 +0000
+++ b/libcore/Bitmap.cpp        2010-08-03 16:53:57 +0000
@@ -34,11 +34,13 @@
     :
     DisplayObject(mr, object, parent),
     _bitmapData(bd),
-    _bitmapInfo(0),
-    _width(_bitmapData->getWidth()),
-    _height(_bitmapData->getHeight())
+    _width(_bitmapData->width()),
+    _height(_bitmapData->height())
 {
-    _shape.setBounds(SWFRect(0, 0, pixelsToTwips(_width), 
pixelsToTwips(_height)));
+    _shape.setBounds(SWFRect(0, 0,
+                pixelsToTwips(_width), pixelsToTwips(_height)));
+    assert(bd);
+    assert(!bd->disposed());
 }
 
 Bitmap::Bitmap(movie_root& mr, as_object* object,
@@ -47,7 +49,6 @@
     DisplayObject(mr, object, parent),
     _def(def),
     _bitmapData(0),
-    _bitmapInfo(0),
     _width(def->get_width_pixels()),
     _height(def->get_height_pixels())
 {
@@ -58,18 +59,45 @@
 {
 }
 
-const BitmapInfo*
+const CachedBitmap*
 Bitmap::bitmap() const
 {
     if (_def) return _def->bitmap();
-    return _bitmapInfo.get();
+    if (_bitmapData) return _bitmapData->bitmapInfo();
+    return 0;
 }
 
 void
 Bitmap::construct(as_object* /*init*/)
 {
-    if (_bitmapData) _bitmapData->registerBitmap(this);
-    update();
+    if (_bitmapData) _bitmapData->attach(this);
+
+    if (!_def && !_bitmapData) return;
+
+    // Width and height are a maximum of 2880, so there is no risk of 
+    // overflow 
+    const int w = pixelsToTwips(_width);
+    const int h = pixelsToTwips(_height);
+
+    SWFMatrix mat;
+    mat.set_scale(1.0 / 20, 1.0 / 20);
+
+    // Can this be tiled? And smoothing?
+    FillStyle fill = BitmapFill(BitmapFill::CLIPPED, bitmap(), mat,
+            BitmapFill::SMOOTHING_UNSPECIFIED);
+
+    const size_t fillLeft = _shape.addFillStyle(fill);
+
+    Path bmpath(w, h, fillLeft, 0, 0, false);
+    bmpath.drawLineTo(w, 0);
+    bmpath.drawLineTo(0, 0);
+    bmpath.drawLineTo(0, h);
+    bmpath.drawLineTo(w, h);
+
+    _shape.add_path(bmpath);
+    _shape.finalize();
+
+    set_invalidated();
 }
 
 bool
@@ -108,89 +136,17 @@
 }
 
 void
-Bitmap::makeBitmap()
-{
-
-    const BitmapData_as::BitmapArray& data = _bitmapData->getBitmapData();
-
-    std::auto_ptr<GnashImage> im(new ImageRGBA(_width, _height)); 
-
-    for (size_t i = 0; i < _height; ++i) {
-
-        boost::uint8_t* row = im->scanline(i);
-
-        for (size_t j = 0; j < _width; ++j) {
-            const BitmapData_as::BitmapArray::value_type pixel =
-                data[i * _width + j];
-            row[j * 4] = (pixel & 0x00ff0000) >> 16;
-            row[j * 4 + 1] = (pixel & 0x0000ff00) >> 8;
-            row[j * 4 + 2] = (pixel & 0x000000ff);
-            row[j * 4 + 3] = (pixel & 0xff000000) >> 24;
-        }
-    }
-
-    Renderer* renderer = stage().runResources().renderer();
-    if (renderer) _bitmapInfo = renderer->createBitmapInfo(im);
-
-}
-
-
-void
-Bitmap::checkBitmapData()
-{
-
+Bitmap::update()
+{
     /// Nothing to do for disposed bitmaps.
-    if (_def && !_bitmapData) return;
-
-    const BitmapData_as::BitmapArray& data = _bitmapData->getBitmapData();
-
-    /// In this case, dispose() was called. It seems like a good idea to
-    /// set _bitmapData to 0 to avoid any further interaction.
-    if (data.empty()) {
+    if (!_bitmapData) return;
+    
+    set_invalidated();
+
+    if (_bitmapData->disposed()) {
         _bitmapData = 0;
         _shape.clear();
-        return;
     }
 }
 
-void
-Bitmap::makeBitmapShape()
-{
-
-    if (!_def && !_bitmapData) return;
-
-    if (_bitmapData) makeBitmap();
-
-    // Width and height are a maximum of 2880, so there is no risk of 
-    // overflow 
-    const int w = pixelsToTwips(_width);
-    const int h = pixelsToTwips(_height);
-
-    SWFMatrix mat;
-    mat.set_scale(1.0 / 20, 1.0 / 20);
-
-    // 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);
-    bmpath.drawLineTo(0, 0);
-    bmpath.drawLineTo(0, h);
-    bmpath.drawLineTo(w, h);
-
-    _shape.add_path(bmpath);
-
-    _shape.finalize();
-
-}
-
-void
-Bitmap::update()
-{
-    set_invalidated();
-    checkBitmapData();
-    makeBitmapShape();
-}
-
 }

=== modified file 'libcore/Bitmap.h'
--- a/libcore/Bitmap.h  2010-06-09 14:39:48 +0000
+++ b/libcore/Bitmap.h  2010-08-03 16:40:04 +0000
@@ -26,7 +26,7 @@
 #include "DynamicShape.h"
 
 namespace gnash {
-    class BitmapInfo;
+    class CachedBitmap;
 }
 
 
@@ -49,28 +49,31 @@
 {
 public:
 
+    /// Construct a Bitmap character from a BitmapData.
        Bitmap(movie_root& mr, as_object* object, BitmapData_as* bd,
             DisplayObject* parent);
        
+    /// Construct a Bitmap character from a loaded image.
     Bitmap(movie_root& mr, as_object* object, const BitmapMovieDefinition* def,
             DisplayObject* parent);
 
-    ~Bitmap();
+    virtual ~Bitmap();
 
-    /// Called to update the Bitmap's DynamicShape for display.
-    //
-    /// For non-dynamic bitmaps, this should only be called once (for
-    /// efficiency - there are no harmful side-effects)
-    void update();
+    /// Notify the Bitmap that it's been updated during ActionScript execution
+    virtual void update();
 
     virtual void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
 
+    /// Display this Bitmap
     virtual void display(Renderer& renderer);
 
+    /// Get the bounds of the Bitmap
     virtual SWFRect getBounds() const;
 
+    /// Test whether a point is in the Bitmap's bounds.
     virtual bool pointInShape(boost::int32_t x, boost::int32_t y) const;
 
+    /// Called when the object is placed on stage.
     virtual void construct(as_object* init = 0);
 
 protected:
@@ -84,10 +87,7 @@
     /// Return the bitmap used for this Bitmap DisplayObject.
     //
     /// It comes either from the definition or the BitmapData_as.
-    const BitmapInfo* bitmap() const;
-
-    /// This updates _bitmapInfo from the BitmapData_as
-    void makeBitmap();
+    const CachedBitmap* bitmap() const;
 
     /// Checks whether an attached BitmapData_as is disposed.
     //
@@ -99,15 +99,10 @@
     //
     /// It should be called every time the underlying bitmap changes; for
     /// non-dynamic Bitmaps, this is only on construction.
-    void makeBitmapShape();
-
     const boost::intrusive_ptr<const BitmapMovieDefinition> _def;
 
     BitmapData_as* _bitmapData;
 
-    /// The current bitmap information is stored here.
-    boost::intrusive_ptr<BitmapInfo> _bitmapInfo;
-
     /// A shape to hold the bitmap fill.
     DynamicShape _shape;
 

=== modified file 'libcore/DisplayObject.h'
--- a/libcore/DisplayObject.h   2010-07-31 16:16:12 +0000
+++ b/libcore/DisplayObject.h   2010-08-03 13:07:36 +0000
@@ -633,7 +633,6 @@
     //
     /// notifyEvent(id) will be called by execution of the queued
     /// action
-    ///
     void queueEvent(const event_id& id, int lvl);
 
     /// Return true if an handler for the given event is defined
@@ -643,7 +642,6 @@
     /// this in a non-virtual function. Main use for this method
     /// is for being called by ::unload() to verify an Unload handler
     /// is available.
-    ///
     bool hasEventHandler(const event_id& id) const;
 
        /// DisplayObjects are not a mouse entity by default.
@@ -658,7 +656,6 @@
     /// point and is not the DisplayObject being dragged or any of its childs.
     //
     /// Point coordinates in global twips.
-    ///
     virtual const DisplayObject* findDropTarget(boost::int32_t x, 
             boost::int32_t y, DisplayObject* dragging) const
     {
@@ -679,7 +676,10 @@
         return _child_invalidated;
     }
 
-    /// @}
+    /// Notify a change in the DisplayObject's appearance.
+    virtual void update() {
+        set_invalidated();
+    }
 
     /// \brief
     /// This function marks the DisplayObject as being modified in aspect

=== modified file 'libcore/FillStyle.cpp'
--- a/libcore/FillStyle.cpp     2010-08-01 07:47:27 +0000
+++ b/libcore/FillStyle.cpp     2010-08-03 19:15:45 +0000
@@ -155,10 +155,12 @@
     }
 }
 
-const BitmapInfo*
+const CachedBitmap*
 BitmapFill::bitmap() const
 {
-    if (_bitmapInfo) return _bitmapInfo.get();
+    if (_bitmapInfo) {
+        return  _bitmapInfo->disposed() ? 0 : _bitmapInfo.get();
+    }
     if (!_md) return 0;
     _bitmapInfo = _md->getBitmap(_id);
 

=== modified file 'libcore/FillStyle.h'
--- a/libcore/FillStyle.h       2010-08-01 06:17:17 +0000
+++ b/libcore/FillStyle.h       2010-08-03 19:15:45 +0000
@@ -26,7 +26,7 @@
 #include <cassert>
 
 #include "SWFMatrix.h"
-#include "BitmapInfo.h"
+#include "CachedBitmap.h"
 #include "SWF.h"
 #include "RGBA.h" // for rgba type
 
@@ -59,7 +59,7 @@
 /// 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
+/// possible to change the appearance of the fill by changing the CachedBitmap
 /// it refers to.
 //
 /// TODO: check the following:
@@ -89,10 +89,11 @@
     /// Construct a BitmapFill from arbitrary bitmap data.
     //
     /// TODO: check the smoothing policy here!
-    BitmapFill(Type t, const BitmapInfo* bi, const SWFMatrix& m)
+    BitmapFill(Type t, const CachedBitmap* bi, const SWFMatrix& m,
+            SmoothingPolicy pol)
         :
         _type(t),
-        _smoothingPolicy(SMOOTHING_UNSPECIFIED),
+        _smoothingPolicy(pol),
         _matrix(m),
         _bitmapInfo(bi),
         _md(0),
@@ -134,7 +135,7 @@
     }
 
     /// Get the actual Bitmap data.
-    const BitmapInfo* bitmap() const;
+    const CachedBitmap* bitmap() const;
 
     /// Get the matrix of this BitmapFill.
     const SWFMatrix& matrix() const {
@@ -150,7 +151,7 @@
     SWFMatrix _matrix;
     
     /// A Bitmap, used for dynamic fills and to cache parsed bitmaps.
-    mutable boost::intrusive_ptr<const BitmapInfo> _bitmapInfo;
+    mutable boost::intrusive_ptr<const CachedBitmap> _bitmapInfo;
 
     /// The movie definition containing the bitmap
     movie_definition* _md;

=== modified file 'libcore/FreetypeGlyphsProvider.cpp'
--- a/libcore/FreetypeGlyphsProvider.cpp        2010-07-31 16:42:49 +0000
+++ b/libcore/FreetypeGlyphsProvider.cpp        2010-08-04 06:37:08 +0000
@@ -23,7 +23,6 @@
 
 #include "FreetypeGlyphsProvider.h"
 #include "smart_ptr.h" // for intrusive_ptr
-#include "GnashImage.h" // for create_alpha
 #include "GnashException.h"
 #include "ShapeRecord.h"
 #include "log.h"

=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am       2010-07-31 14:05:26 +0000
+++ b/libcore/Makefile.am       2010-08-02 10:53:10 +0000
@@ -279,7 +279,6 @@
        MovieFactory.h \
        FillStyle.h \
        LineStyle.h \
-       BitmapInfo.h \
        RGBA.h  \
        Geometry.h      \
        Video.h \

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2010-07-31 14:05:26 +0000
+++ b/libcore/MovieClip.h       2010-08-03 16:40:04 +0000
@@ -50,7 +50,7 @@
     class GradientRecord;
     class TextField;
     class BitmapData_as;
-    class BitmapInfo;
+    class CachedBitmap;
     class GnashImage;
     namespace SWF {
         class PlaceObject2Tag;

=== modified file 'libcore/asobj/MovieClip_as.cpp'
--- a/libcore/asobj/MovieClip_as.cpp    2010-07-31 16:42:49 +0000
+++ b/libcore/asobj/MovieClip_as.cpp    2010-08-03 16:53:57 +0000
@@ -38,6 +38,8 @@
 #include "Array_as.h"
 #include "FillStyle.h"
 #include "namedStrings.h"
+#include "Renderer.h"
+#include "RunResources.h"
 
 namespace gnash {
 
@@ -103,6 +105,8 @@
     as_value movieclip_loadVariables(const fn_call& fn);
     as_value movieclip_dropTarget(const fn_call& fn);
 
+    SWFMatrix asToSWFMatrix(as_object& o);
+
 }
 
 // extern (used by Global.cpp)
@@ -1792,56 +1796,8 @@
         stops = 15;
     }
 
-    SWFMatrix mat;
-
-    // This is case sensitive.
-    if (matrix->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box") {
-        
-        const double valX = pixelsToTwips(
-                matrix->getMember(NSV::PROP_X).to_number()); 
-        const double valY = pixelsToTwips(
-                matrix->getMember(NSV::PROP_Y).to_number()); 
-        const double valW = pixelsToTwips(
-                matrix->getMember(NSV::PROP_W).to_number()); 
-        const double valH = pixelsToTwips(
-                matrix->getMember(NSV::PROP_H).to_number()); 
-        const double rot = matrix->getMember(NSV::PROP_R).to_number(); 
-
-        const double a = std::cos(rot) * valW * 2;
-        const double b = std::sin(rot) * valH * 2;
-        const double c = -std::sin(rot) * valW * 2;
-        const double d = std::cos(rot) * valH * 2;
-
-        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 {
-
-        // Convert input matrix to SWFMatrix.
-        const double factor = 65536.0;
-        const double valA = matrix->getMember(NSV::PROP_A).to_number() * 
factor;
-        const double valB = matrix->getMember(NSV::PROP_B).to_number() * 
factor;
-        const double valC = matrix->getMember(NSV::PROP_C).to_number() * 
factor;
-        const double valD = matrix->getMember(NSV::PROP_D).to_number() * 
factor;
-
-        const boost::int32_t valTX = pixelsToTwips(
-                matrix->getMember(NSV::PROP_TX).to_number());
-        const boost::int32_t valTY = pixelsToTwips(
-                matrix->getMember(NSV::PROP_TY).to_number());
-
-        mat.sx = valA; 
-        mat.shx = valB;
-        mat.shy = valC;
-        mat.sy = valD; 
-        mat.tx = valTX; 
-        mat.ty = valTY;
-    }
-    
+    SWFMatrix mat = asToSWFMatrix(*matrix);
+
     // ----------------------------
     // Create the gradients vector
     // ----------------------------
@@ -2001,8 +1957,50 @@
 movieclip_beginBitmapFill(const fn_call& fn)
 {
     MovieClip* ptr = ensure<IsDisplayObject<MovieClip> >(fn);
-    UNUSED(ptr);
-    LOG_ONCE( log_unimpl (__FUNCTION__) );
+    if (fn.nargs < 1) {
+        return as_value();
+    }
+
+    as_object* obj = fn.arg(0).to_object(getGlobal(fn));
+    BitmapData_as* bd;
+
+    if (!isNativeType(obj, bd) || bd->disposed()) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_debug("MovieClip.attachBitmap: first argument should be a "
+                "valid BitmapData", fn.arg(1));
+        );
+        return as_value();
+    }
+    
+    SWFMatrix mat;
+
+    if (fn.nargs > 1) {
+        as_object* matrix = fn.arg(1).to_object(getGlobal(fn));
+        if (matrix) {
+            mat = asToSWFMatrix(*matrix);
+        }
+    }
+
+    BitmapFill::Type t = BitmapFill::TILED;
+    if (fn.nargs > 2) {
+        const bool repeat = fn.arg(2).to_bool();
+        if (!repeat) t = BitmapFill::CLIPPED;
+    }
+
+    BitmapFill::SmoothingPolicy p = BitmapFill::SMOOTHING_OFF;
+    if (fn.nargs > 3 && fn.arg(3).to_bool()) p = BitmapFill::SMOOTHING_ON;
+
+    // This is needed to get the bitmap to the right size and have it in the
+    // correct place. Maybe it would be better handled somewhere else, as it's
+    // not exactly intuitive.
+    mat.invert();
+    mat.concatenate_scale(1 / 20., 1 / 20.);
+    mat.tx /= 20;
+    mat.ty /= 20;
+
+    ptr->graphics().beginFill(BitmapFill(t, bd->bitmapInfo(), mat, p));
+    bd->attach(ptr);
+
     return as_value();
 }
 
@@ -2044,10 +2042,10 @@
     as_object* obj = fn.arg(0).to_object(getGlobal(fn));
     BitmapData_as* bd;
 
-    if (!isNativeType(obj, bd)) {
+    if (!isNativeType(obj, bd) || bd->disposed()) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_debug("MovieClip.attachBitmap: first argument should be a "
-                "BitmapData", fn.arg(1));
+                "valid BitmapData", fn.arg(1));
         );
         return as_value();
     }
@@ -2114,6 +2112,44 @@
     ptr->setLockRoot(fn.arg(0).to_bool());
     return as_value();
 }
+    
+SWFMatrix
+asToSWFMatrix(as_object& m)
+{
+    // This is case sensitive.
+    if (m.getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box") {
+        
+        const double x = pixelsToTwips(m.getMember(NSV::PROP_X).to_number());
+        const double y = pixelsToTwips(m.getMember(NSV::PROP_Y).to_number());
+        const double w = pixelsToTwips(m.getMember(NSV::PROP_W).to_number());
+        const double h = pixelsToTwips(m.getMember(NSV::PROP_H).to_number()); 
+        const double r = m.getMember(NSV::PROP_R).to_number();
+        const double a = std::cos(r) * w * 2;
+        const double b = std::sin(r) * h * 2;
+        const double c = -std::sin(r) * w * 2;
+        const double d = std::cos(r) * h * 2;
+
+        return SWFMatrix(a, b, c, d, x + w / 2.0, y + h / 2.0);
+        
+    }
+
+    // Convert input matrix to SWFMatrix.
+    const boost::int32_t a = truncateWithFactor<65536>(
+            m.getMember(NSV::PROP_A).to_number());
+    const boost::int32_t b = truncateWithFactor<65536>(
+            m.getMember(NSV::PROP_B).to_number());
+    const boost::int32_t c = truncateWithFactor<65536>(
+            m.getMember(NSV::PROP_C).to_number());
+    const boost::int32_t d = truncateWithFactor<65536>(
+            m.getMember(NSV::PROP_D).to_number());
+
+    const boost::int32_t tx = pixelsToTwips(
+            m.getMember(NSV::PROP_TX).to_number());
+    const boost::int32_t ty = pixelsToTwips(
+            m.getMember(NSV::PROP_TY).to_number());
+    return SWFMatrix(a, b, c, d, tx, ty);
+
+}
 
 } // anonymous namespace 
 } // gnash namespace

=== modified file 'libcore/asobj/flash/display/BitmapData_as.cpp'
--- a/libcore/asobj/flash/display/BitmapData_as.cpp     2010-03-11 01:47:08 
+0000
+++ b/libcore/asobj/flash/display/BitmapData_as.cpp     2010-08-04 06:37:08 
+0000
@@ -19,10 +19,14 @@
 //
 
 #include "BitmapData_as.h"
+
+#include <vector>
+#include <sstream>
+#include <algorithm>
+
 #include "MovieClip.h"
 #include "GnashImage.h"
-#include "Bitmap.h"
-#include "flash/geom/Rectangle_as.h" // for BitmapData.rectangle
+#include "DisplayObject.h"
 #include "as_object.h" // for inheritance
 #include "log.h"
 #include "fn_call.h"
@@ -31,11 +35,9 @@
 #include "builtin_function.h" // need builtin_function
 #include "GnashException.h" // for ActionException
 #include "VM.h" // for addStatics
-
+#include "Renderer.h"
+#include "RunResources.h"
 #include "namedStrings.h"
-#include <vector>
-#include <sstream>
-#include <algorithm>
 
 namespace gnash {
 
@@ -77,77 +79,69 @@
 
 }
 
-
-BitmapData_as::BitmapData_as(as_object* owner, size_t width, size_t height,
-              bool transparent, boost::uint32_t fillColor)
+BitmapData_as::BitmapData_as(as_object* owner, std::auto_ptr<GnashImage> im,
+        boost::uint32_t fillColor)
     :
     _owner(owner),
-    _width(width),
-    _height(height),
-    _transparent(transparent),
-    _bitmapData(width * height, fillColor + (0xff << 24))
+    _cachedBitmap(0)
 {
+    assert(im->width() <= 2880);
+    assert(im->width() <= 2880);
+
+    std::fill(im->argb_begin(), im->argb_end(), fillColor | (0xff << 24));
+    
+    // If there is a renderer, cache the image there, otherwise we store it.
+    Renderer* r = getRunResources(*_owner).renderer();
+    if (r) _cachedBitmap.reset(r->createCachedBitmap(im));
+    else _image.reset(im.release());
 }
-
+    
 void
 BitmapData_as::setReachable() 
 {
-    std::for_each(_attachedBitmaps.begin(), _attachedBitmaps.end(),
+    std::for_each(_attachedObjects.begin(), _attachedObjects.end(),
             std::mem_fun(&DisplayObject::setReachable));
     _owner->setReachable();
-}
-
-
-/// This function should write RGBA data to the _bitmapData array.
-//
-/// TODO: it needs to know what to do about transparency.
-void
-BitmapData_as::update(const boost::uint8_t* data)
-{
-    for (size_t i = 0; i < _width * _height; ++i) {
-        boost::uint32_t pixel = (*(data++) << 16);
-        pixel |= (*(data++) << 8);
-        pixel |= (*(data++));
-        pixel |= (0xff << 24);
-        _bitmapData[i] = pixel;
-    }
-}
-   
-
-void
-BitmapData_as::updateAttachedBitmaps()
-{
-    log_debug("Updating %d attached bitmaps", _attachedBitmaps.size());
-    std::for_each(_attachedBitmaps.begin(), _attachedBitmaps.end(),
-            std::mem_fun(&Bitmap::update));
-}
-
-boost::int32_t
-BitmapData_as::getPixel(int x, int y, bool transparency) const
-{
-    assert(!_bitmapData.empty());
-
-    // A value of 0, 0 is inside the bitmap.
-    if (x < 0 || y < 0) return 0;
-    
-    // A value of _width, _height is outside the bitmap.
-    if (static_cast<size_t>(x) >= _width || static_cast<size_t>(y) >= _height) 
{
-        return 0;
-    }
-
-    const size_t pixelIndex = y * _width + x;
-
-    assert ( pixelIndex < _bitmapData.size());
-    
-    const boost::uint32_t pixel = _bitmapData[pixelIndex];
-    
-    if (transparency)
-    {
-        return static_cast<boost::int32_t>(pixel);
-    }
-    
-    // Without transparency
-    return static_cast<boost::int32_t>(pixel & 0x00ffffff);
+    log_debug("BitmapData_as::setReachable");
+}
+
+void
+BitmapData_as::setPixel32(size_t x, size_t y, boost::uint32_t color)
+{
+    if (disposed()) return;
+    if (x >= width() || y >= height()) return;
+
+    GnashImage::argb_iterator it = data()->argb_begin() + x * width() + y;
+    *it = color;
+}
+
+void
+BitmapData_as::setPixel(size_t x, size_t y, boost::uint32_t color)
+{
+    if (disposed()) return;
+    if (x >= width() || y >= height()) return;
+
+    GnashImage::argb_iterator it = data()->argb_begin() + x * width() + y;
+    const boost::uint32_t val = it.toARGB();
+    *it = (color & 0xffffff) | (val & 0xff000000);
+}
+
+void
+BitmapData_as::updateObjects()
+{
+    log_debug("Updating %d attached objects", _attachedObjects.size());
+    std::for_each(_attachedObjects.begin(), _attachedObjects.end(),
+            std::mem_fun(&DisplayObject::update));
+}
+
+boost::uint32_t
+BitmapData_as::getPixel(size_t x, size_t y) const
+{
+    if (disposed()) return 0;
+    if (x >= width() || y >= height()) return 0;
+
+    const size_t pixelIndex = y * width() + x;
+    return (data()->argb_begin() + pixelIndex).toARGB();
 
 }
 
@@ -155,15 +149,12 @@
 BitmapData_as::fillRect(int x, int y, int w, int h, boost::uint32_t color)
 {
 
-    // This also catches disposed BitmapDatas.
-    assert(_bitmapData.size() == _width * _height);
+    if (disposed()) return;
 
     if (w < 0 || h < 0) return;
-
-    // Nothing to do if x or y are outside the image (negative height
-    // or width are not allowed). The cast to int is fine as neither
-    // dimension can be more than 2880 pixels.
-    if (x >= static_cast<int>(_width) || y >= static_cast<int>(_height)) 
return;
+    if (x >= static_cast<int>(width()) || y >= static_cast<int>(height())) {
+        return;
+    }
 
     // If x or y is less than 0, make a rectangle of the
     // intersection with the bitmap.    
@@ -182,34 +173,30 @@
     // the bitmap.    
     if (w <= 0 || h <= 0) return;
 
-    w = std::min<size_t>(_width - x, w);
-    h = std::min<size_t>(_height - y, h);
-    
-    BitmapArray::iterator it = _bitmapData.begin() + y * _width;
-    
-    // This cannot be past .end() because h + y is no larger than the
-    // height of the image.
-    const BitmapArray::iterator e = it + _width * h;
-    
-    // Make colour non-transparent if the image doesn't support it.
-    if (!_transparent) color |= 0xff000000;
+    w = std::min<size_t>(width() - x, w);
+    h = std::min<size_t>(height() - y, h);
+    
+    GnashImage::argb_iterator it = data()->argb_begin() + y * width();
+    
+    GnashImage::argb_iterator e = it + width() * h;
     
     while (it != e) {
         // Fill from x for the width of the rectangle.
         std::fill_n(it + x, w, color);
-        // Move to the next line
-        std::advance(it, _width);
+        it += width();
     }
 
-    updateAttachedBitmaps();
+    updateObjects();
 
 }
 
 void
 BitmapData_as::dispose()
 {
-    _bitmapData.clear();
-    updateAttachedBitmaps();
+    if (_cachedBitmap) _cachedBitmap->dispose();
+    _cachedBitmap.reset();
+    _image.reset();
+    updateObjects();
 }
 
 // extern 
@@ -284,6 +271,7 @@
 bitmapdata_draw(const fn_call& fn)
 {
        BitmapData_as* ptr = ensure<ThisIsNative<BitmapData_as> >(fn);
+    UNUSED(ptr);
 
     std::ostringstream os;
     fn.dump_args(os);
@@ -317,7 +305,7 @@
         return as_value();
     }
 
-    ptr->update(im->data());
+    //ptr->update(im->data());
 
        return as_value();
 }
@@ -329,13 +317,6 @@
 
     if (fn.nargs < 2) return as_value();
     
-    if (disposed(*ptr)) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror("fillRect called on disposed BitmapData!");
-        );
-        return as_value();
-    }
-    
     const as_value& arg = fn.arg(0);
     
     if (!arg.is_object()) {
@@ -405,18 +386,19 @@
         return as_value();
     }
 
-    if (disposed(*ptr)) {
+    if (ptr->disposed()) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_aserror("getPixel called on disposed BitmapData!");
         );
         return as_value();
     }
     
-    // TODO: what happens when the pixel is outside the image?
     const int x = toInt(fn.arg(0));
     const int y = toInt(fn.arg(1));
     
-    return ptr->getPixel(x, y, false);
+    // Will return 0 if the pixel is outside the image or the image has
+    // been disposed.
+    return static_cast<boost::int32_t>(ptr->getPixel(x, y) & 0xffffff);
 }
 
 as_value
@@ -428,7 +410,7 @@
         return as_value();
     }
 
-    if (disposed(*ptr)) {
+    if (ptr->disposed()) {
         IF_VERBOSE_ASCODING_ERRORS(
             log_aserror("getPixel32 called on disposed BitmapData!");
         );
@@ -439,7 +421,7 @@
     const int x = toInt(fn.arg(0));
     const int y = toInt(fn.arg(1));
     
-    return ptr->getPixel(x, y, true);
+    return static_cast<boost::int32_t>(ptr->getPixel(x, y));
 }
 
 
@@ -515,22 +497,15 @@
         return as_value();
     }
 
-    if (disposed(*ptr)) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror("setPixel called on disposed BitmapData!");
-        );
-        return as_value();
-    }
-
     const double x = fn.arg(0).to_number();
     const double y = fn.arg(1).to_number();
     if (isNaN(x) || isNaN(y) || x < 0 || y < 0) return as_value();
-    if (x >= ptr->getWidth() || y >= ptr->getHeight()) {
+    if (x >= ptr->width() || y >= ptr->height()) {
         return as_value();
     }
 
     // Ignore any transparency here.
-    const boost::uint32_t color = toInt(fn.arg(2)) & 0xffffff;
+    const boost::uint32_t color = toInt(fn.arg(2));
 
     ptr->setPixel(x, y, color);
 
@@ -546,17 +521,10 @@
         return as_value();
     }
 
-    if (disposed(*ptr)) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror("setPixel32 called on disposed BitmapData!");
-        );
-        return as_value();
-    }
-
     const double x = fn.arg(0).to_number();
     const double y = fn.arg(1).to_number();
     if (isNaN(x) || isNaN(y) || x < 0 || y < 0) return as_value();
-    if (x >= ptr->getWidth() || y >= ptr->getHeight()) {
+    if (x >= ptr->width() || y >= ptr->height()) {
         return as_value();
     }
 
@@ -587,8 +555,8 @@
     
     // Returns the immutable height of the bitmap or -1 if dispose() has
     // been called.
-    if (disposed(*ptr)) return -1;
-       return as_value(ptr->getHeight());
+    if (ptr->disposed()) return -1;
+       return as_value(ptr->height());
 }
 
 as_value
@@ -598,7 +566,7 @@
 
     // Returns the immutable rectangle of the bitmap or -1 if dispose()
     // has been called.
-    if (disposed(*ptr)) return -1;
+    if (ptr->disposed()) return -1;
 
     // If it's not found construction will fail.
     as_value rectangle(fn.env().find_object("flash.geom.Rectangle"));
@@ -610,7 +578,7 @@
     }
 
     fn_call::Args args;
-    args += 0.0, 0.0, ptr->getWidth(), ptr->getHeight();
+    args += 0.0, 0.0, ptr->width(), ptr->height();
 
     boost::intrusive_ptr<as_object> newRect =
             constructInstance(*rectCtor, fn.env(), args);
@@ -627,8 +595,8 @@
     if (fn.nargs) return as_value();
     
     // Returns whether bitmap is transparent or -1 if dispose() has been 
called.
-    if (disposed(*ptr)) return -1;
-       return as_value(ptr->isTransparent());
+    if (ptr->disposed()) return -1;
+       return as_value(ptr->transparent());
 }
 
 as_value
@@ -641,8 +609,8 @@
     
     // Returns the immutable width of the bitmap or -1 if dispose() has
     // been called.
-    if (disposed(*ptr)) return -1;
-       return as_value(ptr->getWidth());
+    if (ptr->disposed()) return -1;
+       return as_value(ptr->width());
 }
 
 
@@ -680,26 +648,11 @@
         throw ActionTypeError();
        }
 
-    size_t width, height;
-    bool transparent = true;
-    boost::uint32_t fillColor = 0xffffff;
-
-    switch (fn.nargs)
-    {
-        default:
-            // log AS coding error
-        case 4:
-            fillColor = toInt(fn.arg(3));
-        case 3:
-            transparent = fn.arg(2).to_bool();
-        case 2:
-            // Is to_int correct?
-            height = toInt(fn.arg(1));
-            width = toInt(fn.arg(0));
-            break;
-    }
+    size_t width = toInt(fn.arg(0));
+    size_t height = toInt(fn.arg(1));
+    bool transparent = fn.nargs > 2 ? fn.arg(2).to_bool() : true;
+    boost::uint32_t fillColor = fn.nargs > 3 ? toInt(fn.arg(3)) : 0xffffff;
     
-    // FIXME: Should fail to construct the object.
     if (width > 2880 || height > 2880 || width < 1 || height < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
              log_aserror("BitmapData width and height must be between "
@@ -708,8 +661,15 @@
         throw ActionTypeError();
     }
 
-    ptr->setRelay(
-            new BitmapData_as(ptr, width, height, transparent, fillColor));
+    std::auto_ptr<GnashImage> im;
+    if (transparent) {
+        im.reset(new ImageRGBA(width, height));
+    }
+    else {
+        im.reset(new ImageRGB(width, height));
+    }
+
+    ptr->setRelay(new BitmapData_as(ptr, im, fillColor));
 
        return as_value(); 
 }

=== modified file 'libcore/asobj/flash/display/BitmapData_as.h'
--- a/libcore/asobj/flash/display/BitmapData_as.h       2010-06-05 09:29:30 
+0000
+++ b/libcore/asobj/flash/display/BitmapData_as.h       2010-08-03 16:40:04 
+0000
@@ -21,124 +21,126 @@
 #ifndef GNASH_ASOBJ_BITMAPDATA_H
 #define GNASH_ASOBJ_BITMAPDATA_H
 
-#include "Relay.h"
-
 #include <list>
-#include <vector>
 #include <boost/cstdint.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <cassert>
-
-namespace gnash {
-
-class as_function;
-class as_object;
-struct ObjectURI;
-class Bitmap;
-
+#include "smart_ptr.h"
+#include <boost/intrusive_ptr.hpp>
+#include <memory>
+
+#include "Relay.h"
+#include "CachedBitmap.h"
+#include "GnashImage.h"
+
+namespace gnash {
+    class as_object;
+    struct ObjectURI;
+    class DisplayObject;
+    class GnashImage;
+}
+
+namespace gnash {
 
 /// Implements the BitmapData native type.
 //
-/// This holds a vector of bitmap data. The vector's size does not change
-/// from construction until disposal. Disposal is signified by the clearing
-/// of the vector. All callers should check whether the BitmapData has been
-/// disposed before attempting to access any stored pixel data.
+/// All functions can be called if the BitmapData has been disposed. Callers
+/// do not need to check.
 class BitmapData_as : public Relay
 {
 
 public:
 
-    typedef std::vector<boost::uint32_t> BitmapArray;
-
-    // The constructor sets the fill colour and the
-    // immutable size of the bitmap, as well as whether
-    // it can handle transparency or not.
-       BitmapData_as(as_object* owner, size_t width, size_t height,
-                     bool transparent, boost::uint32_t fillColor);
-
-    size_t getWidth() const { return _width; }
-    size_t getHeight() const { return _height; }
-    bool isTransparent() const { return _transparent; }
+    /// Construct a BitmapData.
+    //
+    /// The constructor sets the fill colour and the immutable size of the
+    /// bitmap, as well as whether it can handle transparency or not.
+       BitmapData_as(as_object* owner, std::auto_ptr<GnashImage> im,
+                     boost::uint32_t fillColor);
+
+    virtual ~BitmapData_as() {}
+
+    /// Return the width of the image
+    //
+    /// Do not call if disposed!
+    size_t width() const {
+        assert(data());
+        return data()->width();
+    }
     
-    const BitmapArray& getBitmapData() const {
-        return _bitmapData;
-    }
- 
-    /// Set a specified pixel to the specified color.
-    //
-    /// Callers must make sure the pixel is in range and that the
-    /// BitmapData has not been disposed. Retains transparency
-    /// (which is opaque, for non-transparent BitmapData objects).
-    void setPixel(int x, int y, boost::uint32_t color) {
-        assert(!_bitmapData.empty());
-        const BitmapArray::size_type index = x * _width + y;
-        _bitmapData[index] = (_bitmapData[index] & 0xff000000) | color;
-    }
-
-    /// Set a specified pixel to the specified color.
-    //
-    /// Callers must make sure the pixel is in range and that the BitmapData
-    /// has not been disposed. Set to opaque for non-transparent BitmapData
-    /// objects
-    void setPixel32(int x, int y, boost::uint32_t color) {
-        assert(!_bitmapData.empty());
-        _bitmapData[x * _width + y] = _transparent ? color : color | 
0xff000000;
-    }
-
-    /// Returns the value of the pixel at (x, y) optionally with transparency.
-    //
-    /// Callers must make that dispose() has not been called.
-    /// Returns 0 if the pixel is out of range.
-    boost::int32_t getPixel(int x, int y, bool transparency) const;
-
-    void update(const boost::uint8_t* data);
+    /// Return the height of the image
+    //
+    /// Do not call if disposed!
+    size_t height() const {
+        assert(data());
+        return data()->height();
+    }
+
+    bool transparent() const {
+        assert(data());
+        return (data()->type() == GNASH_IMAGE_RGBA);
+    }
+
+    const CachedBitmap* bitmapInfo() const {
+        return _cachedBitmap.get();
+    }
+
+    /// Set a specified pixel to the specified color.
+    //
+    /// Retains transparency value for BitmapDatas with transparency.
+    void setPixel(size_t x, size_t y, boost::uint32_t color);
+
+    /// Set a specified pixel to the specified color.
+    void setPixel32(size_t x, size_t y, boost::uint32_t color);
+
+    /// Returns the value of the pixel at (x, y).
+    //
+    /// Returns 0 if the pixel is out of range or the image has been disposed.
+    boost::uint32_t getPixel(size_t x, size_t y) const;
 
     /// Fill the bitmap with a colour starting at x, y
     //
-    /// Callers must check that arguments are within the BitmapData's range
-    /// and that dispose() has not been called.
+    /// Negative values are handled correctly.
     void fillRect(int x, int y, int w, int h, boost::uint32_t color);
     
-    // Free the bitmap data (clear the array)
+    /// Free the bitmap data
     void dispose();
 
-    void registerBitmap(Bitmap* bitmap) {
-        _attachedBitmaps.push_back(bitmap);
+    /// Attach this BitmapData to an object
+    //
+    /// This may be either as a fill or an attached Bitmap.
+    void attach(DisplayObject* obj) {
+        _attachedObjects.push_back(obj);
     }
 
     /// Overrides Relay::setReachable().
     virtual void setReachable();
 
+    /// Whether the BitmapData has been disposed.
+    bool disposed() const {
+        return !data();
+    }
+
 private:
+    
+    GnashImage* data() const {
+        return _cachedBitmap.get() ? &_cachedBitmap->image() : _image.get();
+    }
 
-    void updateAttachedBitmaps();
+    /// Inform any attached objects that the data has changed.
+    void updateObjects();
 
     /// The object to which this native type class belongs to.
     as_object* _owner;
 
-    // The width of the image, max 2880. This is immutable.
-    const size_t _width;
-    
-    // The height of the image, max 2880. This is immutable.
-    const size_t _height;
-    
-    // Whether the image is transparent. This is immutable.
-    const bool _transparent;
-
-    // A static array of 32-bit values holding the actual bitmap data.
-    // The maximum size is 2880 x 2880 * 4 bytes = 33177600 bytes.
-    BitmapArray _bitmapData;
-
-    std::list<Bitmap*> _attachedBitmaps;
+    boost::intrusive_ptr<CachedBitmap> _cachedBitmap;
+
+    boost::scoped_ptr<GnashImage> _image;
+
+    std::list<DisplayObject*> _attachedObjects;
 
 };
 
-inline bool
-disposed(const BitmapData_as& bm)
-{
-    return bm.getBitmapData().empty();
-}
-
-
 /// Initialize the global BitmapData class
 void bitmapdata_class_init(as_object& where, const ObjectURI& uri);
 

=== modified file 'libcore/parser/BitmapMovieDefinition.cpp'
--- a/libcore/parser/BitmapMovieDefinition.cpp  2010-07-28 07:57:23 +0000
+++ b/libcore/parser/BitmapMovieDefinition.cpp  2010-08-03 16:40:04 +0000
@@ -27,7 +27,7 @@
 #include "Renderer.h"
 #include "Global_as.h"
 #include "namedStrings.h"
-#include "BitmapInfo.h"
+#include "CachedBitmap.h"
 
 namespace gnash {
 
@@ -47,7 +47,7 @@
        _framerate(12),
        _url(url),
        _bytesTotal(image->size()),
-       _bitmap(renderer ? renderer->createBitmapInfo(image) : 0)
+       _bitmap(renderer ? renderer->createCachedBitmap(image) : 0)
 {
 }
 

=== modified file 'libcore/parser/BitmapMovieDefinition.h'
--- a/libcore/parser/BitmapMovieDefinition.h    2010-07-19 08:08:00 +0000
+++ b/libcore/parser/BitmapMovieDefinition.h    2010-08-03 16:40:04 +0000
@@ -118,7 +118,7 @@
                return 1;
        }
 
-    const BitmapInfo* bitmap() const {
+    const CachedBitmap* bitmap() const {
         return _bitmap.get();
     }
 
@@ -134,7 +134,7 @@
 
        size_t _bytesTotal;
 
-    boost::intrusive_ptr<BitmapInfo> _bitmap;
+    boost::intrusive_ptr<CachedBitmap> _bitmap;
 };
 
 } // namespace gnash

=== modified file 'libcore/parser/SWFMovieDefinition.cpp'
--- a/libcore/parser/SWFMovieDefinition.cpp     2010-07-28 07:57:23 +0000
+++ b/libcore/parser/SWFMovieDefinition.cpp     2010-08-03 16:40:04 +0000
@@ -52,7 +52,7 @@
 #include "Global_as.h"
 #include "namedStrings.h"
 #include "as_function.h"
-#include "BitmapInfo.h"
+#include "CachedBitmap.h"
 
 // Debug frames load
 #undef DEBUG_FRAMES_LOAD
@@ -224,7 +224,7 @@
     return 0;
 }
 
-BitmapInfo*
+CachedBitmap*
 SWFMovieDefinition::getBitmap(int id) const
 {
     const Bitmaps::const_iterator it = _bitmaps.find(id);
@@ -233,7 +233,7 @@
 }
 
 void
-SWFMovieDefinition::addBitmap(int id, boost::intrusive_ptr<BitmapInfo> im)
+SWFMovieDefinition::addBitmap(int id, boost::intrusive_ptr<CachedBitmap> im)
 {
     assert(im);
     _bitmaps.insert(std::make_pair(id, im));

=== modified file 'libcore/parser/SWFMovieDefinition.h'
--- a/libcore/parser/SWFMovieDefinition.h       2010-07-19 08:08:00 +0000
+++ b/libcore/parser/SWFMovieDefinition.h       2010-08-03 16:40:04 +0000
@@ -256,10 +256,10 @@
     Font* get_font(const std::string& name, bool bold, bool italic) const;
 
     // See dox in movie_definition.h
-    BitmapInfo* getBitmap(int DisplayObject_id) const;
+    CachedBitmap* getBitmap(int DisplayObject_id) const;
 
     // See dox in movie_definition.h
-    void addBitmap(int DisplayObject_id, boost::intrusive_ptr<BitmapInfo> im);
+    void addBitmap(int DisplayObject_id, boost::intrusive_ptr<CachedBitmap> 
im);
 
     // See dox in movie_definition.h
     sound_sample* get_sound_sample(int DisplayObject_id) const;
@@ -425,7 +425,7 @@
     typedef std::map<int, boost::intrusive_ptr<Font> > FontMap;
     FontMap m_fonts;
 
-    typedef std::map<int, boost::intrusive_ptr<BitmapInfo> > Bitmaps;
+    typedef std::map<int, boost::intrusive_ptr<CachedBitmap> > Bitmaps;
     Bitmaps _bitmaps;
 
     typedef std::map<int, boost::intrusive_ptr<sound_sample> > SoundSampleMap;

=== modified file 'libcore/parser/movie_definition.h'
--- a/libcore/parser/movie_definition.h 2010-07-19 08:08:00 +0000
+++ b/libcore/parser/movie_definition.h 2010-08-03 16:40:04 +0000
@@ -64,7 +64,7 @@
 
 // Forward declarations
 namespace gnash {
-       class BitmapInfo;
+       class CachedBitmap;
        class Movie;
        class MovieClip;
        namespace SWF {
@@ -340,7 +340,7 @@
        ///
        /// The default implementation returns 0.
        ///
-       virtual BitmapInfo* getBitmap(int /*DisplayObject_id*/) const
+       virtual CachedBitmap* getBitmap(int /*DisplayObject_id*/) const
        {
                return 0;
        }
@@ -351,7 +351,7 @@
        //
        /// The default implementation is a no-op (deletes the image data).
        ///
-       virtual void addBitmap(int /*id*/, boost::intrusive_ptr<BitmapInfo> 
/*im*/)
+       virtual void addBitmap(int /*id*/, boost::intrusive_ptr<CachedBitmap> 
/*im*/)
        {
        }
 

=== modified file 'libcore/parser/sprite_definition.h'
--- a/libcore/parser/sprite_definition.h        2010-07-26 06:14:03 +0000
+++ b/libcore/parser/sprite_definition.h        2010-08-03 16:40:04 +0000
@@ -156,13 +156,13 @@
        }
 
        /// Delegate call to associated root movie
-       virtual BitmapInfo* getBitmap(int id) const
+       virtual CachedBitmap* getBitmap(int id) const
        {
                return m_movie_def.getBitmap(id);
        }
 
        /// Overridden just for complaining  about malformed SWF
-       virtual void addBitmap(int /*id*/, boost::intrusive_ptr<BitmapInfo> 
/*im*/)
+       virtual void addBitmap(int /*id*/, boost::intrusive_ptr<CachedBitmap> 
/*im*/)
        {
                IF_VERBOSE_MALFORMED_SWF (
                log_swferror(_("add_bitmap_SWF::DefinitionTag appears in sprite 
tags"));

=== modified file 'libcore/swf/tag_loaders.cpp'
--- a/libcore/swf/tag_loaders.cpp       2010-07-29 06:24:31 +0000
+++ b/libcore/swf/tag_loaders.cpp       2010-08-03 16:40:04 +0000
@@ -55,7 +55,7 @@
 #include "RunResources.h"
 #include "Renderer.h"
 #include "Movie.h"
-#include "BitmapInfo.h"
+#include "CachedBitmap.h"
 
 #ifdef HAVE_ZLIB_H
 #include <zlib.h>
@@ -322,7 +322,7 @@
         IF_VERBOSE_PARSE(log_parse(_("No renderer, not adding bitmap")));
         return;
     }    
-    boost::intrusive_ptr<BitmapInfo> bi = renderer->createBitmapInfo(im);
+    boost::intrusive_ptr<CachedBitmap> bi = renderer->createCachedBitmap(im);
 
     // add bitmap to movie under DisplayObject id.
     m.addBitmap(id, bi);
@@ -384,7 +384,7 @@
         IF_VERBOSE_PARSE(log_parse(_("No renderer, not adding bitmap")));
         return;
     }    
-    boost::intrusive_ptr<BitmapInfo> bi = renderer->createBitmapInfo(im);
+    boost::intrusive_ptr<CachedBitmap> bi = renderer->createCachedBitmap(im);
 
     // add bitmap to movie under DisplayObject id.
     m.addBitmap(id, bi);
@@ -539,8 +539,8 @@
         IF_VERBOSE_PARSE(log_parse(_("No renderer, not adding bitmap")));
         return;
     }    
-    boost::intrusive_ptr<BitmapInfo> bi =
-        renderer->createBitmapInfo(static_cast<std::auto_ptr<GnashImage> 
>(im));
+    boost::intrusive_ptr<CachedBitmap> bi =
+        renderer->createCachedBitmap(static_cast<std::auto_ptr<GnashImage> 
>(im));
 
     // add bitmap to movie under DisplayObject id.
     m.addBitmap(id, bi);
@@ -646,8 +646,7 @@
     inflate_wrapper(in, buffer.get(), bufSize);
     assert(in.tell() <= in.get_tag_end_position());
 
-    switch (bitmap_format)
-    {
+    switch (bitmap_format) {
 
         case 3:
         {
@@ -659,7 +658,7 @@
                 boost::uint8_t* inRow = buffer.get() + 
                     colorTableSize * channels + j * pitch;
 
-                boost::uint8_t*    outRow = image->scanline(j);
+                boost::uint8_t* outRow = scanline(*image, j);
                 for (int i = 0; i < width; i++)
                 {
                     boost::uint8_t pixel = inRow[i * bytes_per_pixel];
@@ -681,7 +680,7 @@
             for (int j = 0; j < height; j++)
             {
                 boost::uint8_t* inRow = buffer.get() + j * pitch;
-                boost::uint8_t* outRow = image->scanline(j);
+                boost::uint8_t* outRow = scanline(*image, j);
                 for (int i = 0; i < width; i++)
                 {
                     boost::uint16_t pixel = inRow[i * 2] |
@@ -708,7 +707,7 @@
             for (int j = 0; j < height; j++)
             {
                 boost::uint8_t* inRow = buffer.get() + j * pitch;
-                boost::uint8_t* outRow = image->scanline(j);
+                boost::uint8_t* outRow = scanline(*image, j);
                 const int inChannels = 4;
 
                 for (int i = 0; i < width; ++i)
@@ -732,7 +731,7 @@
         IF_VERBOSE_PARSE(log_parse(_("No renderer, not adding bitmap")));
         return;
     }    
-    boost::intrusive_ptr<BitmapInfo> bi = renderer->createBitmapInfo(image);
+    boost::intrusive_ptr<CachedBitmap> bi = 
renderer->createCachedBitmap(image);
 
     // add bitmap to movie under DisplayObject id.
     m.addBitmap(id, bi);

=== modified file 'libmedia/ffmpeg/VideoDecoderFfmpeg.cpp'
--- a/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp    2010-07-22 20:21:00 +0000
+++ b/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp    2010-08-03 12:37:23 +0000
@@ -316,7 +316,7 @@
     // Let ffmpeg write directly to the GnashImage data. It is an uninitialized
     // buffer here, so do not return the image if there is any error in
     // conversion.
-    avpicture_fill(&picture, im->data(), pixFmt, width, height);
+    avpicture_fill(&picture, im->begin(), pixFmt, width, height);
 
 #ifndef HAVE_SWSCALE_H
     img_convert(&picture, PIX_FMT_RGB24, (AVPicture*)srcFrame,

=== modified file 'libmedia/gst/VideoDecoderGst.h'
--- a/libmedia/gst/VideoDecoderGst.h    2010-01-25 18:52:20 +0000
+++ b/libmedia/gst/VideoDecoderGst.h    2010-08-04 06:59:22 +0000
@@ -40,7 +40,7 @@
 {
 public:
   gnashGstBuffer(GstBuffer* buf, int width, int height)
-  : ImageRGB(NULL, width, height, (width * 3 + 3) & ~3),
+  : ImageRGB(NULL, width, height),
     _buffer(buf)
   {}
   
@@ -49,18 +49,18 @@
     gst_buffer_unref(_buffer);
   }
   
-  boost::uint8_t* data()
-  {
-    return GST_BUFFER_DATA(_buffer);
-  }
-
-  const boost::uint8_t* data() const
-  {
-    return GST_BUFFER_DATA(_buffer);
-  }
-  std::auto_ptr<GnashImage> clone() const
-  {
-    return std::auto_ptr<GnashImage>(new ImageRGB(*this));
+  virtual size_t stride() const {
+      return (width() * channels() + 3) &~ 3;
+  }
+
+  virtual iterator begin()
+  {
+    return GST_BUFFER_DATA(_buffer);
+  }
+
+  virtual const_iterator begin() const
+  {
+    return GST_BUFFER_DATA(_buffer);
   }
 
 private:

=== modified file 'librender/Renderer.h'
--- a/librender/Renderer.h      2010-07-31 14:05:26 +0000
+++ b/librender/Renderer.h      2010-08-03 16:40:04 +0000
@@ -160,7 +160,7 @@
 
 // Forward declarations.
 namespace gnash {
-    class BitmapInfo;
+    class CachedBitmap;
     class rgba;
     class SWFMatrix;
     class cxform;
@@ -221,7 +221,7 @@
     /// Given an image, returns a pointer to a bitmap_info class
     /// that can later be passed to FillStyleX_bitmap(), to set a
     /// bitmap fill style.
-    virtual BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im) = 0;
+    virtual CachedBitmap* createCachedBitmap(std::auto_ptr<GnashImage> im) = 0;
 
 
     /// ==================================================================

=== modified file 'librender/Renderer_agg.cpp'
--- a/librender/Renderer_agg.cpp        2010-07-31 15:15:34 +0000
+++ b/librender/Renderer_agg.cpp        2010-08-03 16:40:04 +0000
@@ -583,8 +583,8 @@
     VideoRenderer(const ClipBounds& clipbounds, GnashImage& frame,
             Matrix& mat, Quality quality, bool smooth)
         :
-        _buf(frame.data(), frame.width(), frame.height(),
-                frame.pitch()),
+        _buf(frame.begin(), frame.width(), frame.height(),
+                frame.stride()),
         _pixf(_buf),
         _accessor(_pixf),
         _interpolator(mat),
@@ -780,7 +780,7 @@
     // Given an image, returns a pointer to a bitmap_info class
     // that can later be passed to FillStyleX_bitmap(), to set a
     // bitmap fill style.
-    gnash::BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im)
+    gnash::CachedBitmap* createCachedBitmap(std::auto_ptr<GnashImage> im)
     {        
         return new agg_bitmap_info(im);
     }

=== modified file 'librender/Renderer_agg_bitmap.h'
--- a/librender/Renderer_agg_bitmap.h   2010-01-11 06:41:38 +0000
+++ b/librender/Renderer_agg_bitmap.h   2010-08-03 17:24:06 +0000
@@ -19,37 +19,48 @@
 #ifndef BACKEND_RENDER_HANDLER_AGG_BITMAP_H
 #define BACKEND_RENDER_HANDLER_AGG_BITMAP_H
 
+#include <boost/scoped_ptr.hpp>
+
 // This include file used only to make Renderer_agg more readable.
 
 namespace gnash {
 
-/// The class itself uses a template. Currently this is unnecessary and it may
-/// be removed but an older implementation required this method and it may be
-/// necessary again when the last missing parts of the renderer will be
-/// implemented. And when might that be? I don't think I'll wait.
-class agg_bitmap_info : public BitmapInfo
+class agg_bitmap_info : public CachedBitmap
 {
 public:
+  
+    agg_bitmap_info(std::auto_ptr<GnashImage> im)
+        :
+        _image(im.release()),
+        _bpp(_image->type() == GNASH_IMAGE_RGB ? 24 : 32)
+    {
+    }
+  
+    virtual GnashImage& image() {
+        assert(!disposed());
+        return *_image;
+    }
+  
+    virtual void dispose() {
+        _image.reset();
+    }
 
-  agg_bitmap_info(std::auto_ptr<GnashImage> im)
-      :
-      _image(im),
-      _bpp(_image->type() == GNASH_IMAGE_RGB ? 24 : 32)
-  {
-  }
- 
-  int get_width() const { return _image->width(); }  
-  int get_height() const { return _image->height();  }  
-  int get_bpp() const { return _bpp; }  
-  int get_rowlen() const { return _image->pitch(); }  
-  boost::uint8_t* get_data() const { return _image->data(); }
-  
+    virtual bool disposed() const {
+        return !_image.get();
+    }
+   
+    int get_width() const { return _image->width(); }  
+    int get_height() const { return _image->height();  }  
+    int get_bpp() const { return _bpp; }  
+    int get_rowlen() const { return _image->stride(); }  
+    boost::uint8_t* get_data() const { return _image->begin(); }
+    
 private:
-
-  std::auto_ptr<GnashImage> _image;
-
-  int _bpp;
-    
+  
+    boost::scoped_ptr<GnashImage> _image;
+  
+    int _bpp;
+      
 };
 
 

=== modified file 'librender/Renderer_cairo.cpp'
--- a/librender/Renderer_cairo.cpp      2010-07-31 16:32:49 +0000
+++ b/librender/Renderer_cairo.cpp      2010-08-03 17:24:06 +0000
@@ -47,6 +47,7 @@
 #include <cmath>
 #include <cairo/cairo.h>
 #include <boost/scoped_array.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <boost/bind.hpp>
 
 namespace gnash {
@@ -60,25 +61,114 @@
 
 namespace {
 
-class bitmap_info_cairo : public BitmapInfo, boost::noncopyable
+// 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 = scanline(*im, 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 = scanline(*im, 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;
+            }
+        }
+    }
+}
+
+class bitmap_info_cairo : public CachedBitmap, boost::noncopyable
 {
   public:
     bitmap_info_cairo(boost::uint8_t* data, int width, int height,
                            size_t bpp, cairo_format_t format)
-    : _data(data),
-      _width(width),
-      _height(height),
-      _bytes_per_pixel(bpp),
-      _format(format),
-      _surface(cairo_image_surface_create_for_data(_data.get(),
-               format, width, height, width * bpp)),
-      _pattern(cairo_pattern_create_for_surface (_surface))
+        :
+        _data(data),
+        _width(width),
+        _height(height),
+        _bytes_per_pixel(bpp),
+        _format(format),
+        _surface(cairo_image_surface_create_for_data(_data.get(),
+                 format, width, height, width * bpp)),
+        _pattern(cairo_pattern_create_for_surface (_surface))
     {
       
       assert(cairo_surface_status(_surface) == CAIRO_STATUS_SUCCESS);
       assert(cairo_pattern_status(_pattern) == CAIRO_STATUS_SUCCESS);
     }
+
+    virtual void dispose() {
+        _image.reset();
+        _data.reset();
+    }
+
+    virtual bool disposed() const {
+        return !_data.get();
+    }
+   
     
+    GnashImage& image() {
+        if (_image.get()) return *_image;
+
+        switch (_format) {
+            case CAIRO_FORMAT_RGB24:
+                _image.reset(new ImageRGB(_width, _height));
+                break;
+
+            case CAIRO_FORMAT_ARGB32:
+                _image.reset(new ImageRGBA(_width, _height));
+                break;
+
+            default:
+                std::abort();
+        }
+
+        // We assume that cairo uses machine-endian order, as that's what
+        // the existing conversion functions do.
+        boost::uint32_t* start =
+            reinterpret_cast<boost::uint32_t*>(_data.get());
+        const size_t sz = _width * _height;
+        std::copy(start, start + sz, _image->argb_begin());
+        return *_image;
+    }
+
+    void update() const {
+        if (!_image.get()) return;
+        switch (_format) {
+            case CAIRO_FORMAT_RGB24:
+                rgb_to_cairo_rgb24(_data.get(), _image.get());
+                break;
+            case CAIRO_FORMAT_ARGB32:
+                rgba_to_cairo_argb(_data.get(), _image.get());
+                break;
+            default:
+                break;
+        }
+        _image.reset();
+    }
+
     ~bitmap_info_cairo()
     {
       cairo_surface_destroy(_surface);
@@ -89,6 +179,7 @@
     {
       assert(mat);
       assert(_pattern);
+      update();
       cairo_pattern_set_matrix(_pattern, mat);
       
       cairo_extend_t extend = CAIRO_EXTEND_REPEAT;
@@ -112,6 +203,7 @@
     }
    
   private:
+    mutable boost::scoped_ptr<GnashImage> _image;
     boost::scoped_array<boost::uint8_t> _data;
     int _width;
     int _height;
@@ -205,44 +297,6 @@
 
 }
 
-// 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)
@@ -398,8 +452,8 @@
     cairo_destroy(_cr);
 }
 
-BitmapInfo*
-Renderer_cairo::createBitmapInfo(std::auto_ptr<GnashImage> im) 
+CachedBitmap*
+Renderer_cairo::createCachedBitmap(std::auto_ptr<GnashImage> im) 
 {
     int buf_size = im->width() * im->height() * 4;
     boost::uint8_t* buffer = new boost::uint8_t[buf_size];

=== modified file 'librender/Renderer_cairo.h'
--- a/librender/Renderer_cairo.h        2010-07-31 14:05:26 +0000
+++ b/librender/Renderer_cairo.h        2010-08-03 16:40:04 +0000
@@ -38,7 +38,7 @@
     Renderer_cairo();
     ~Renderer_cairo();
 
-    BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im);
+    CachedBitmap* createCachedBitmap(std::auto_ptr<GnashImage> im);
 
     void drawVideoFrame(GnashImage* baseframe, const SWFMatrix* m,
                                 const SWFRect* bounds, bool smooth);

=== modified file 'librender/Renderer_ogl.cpp'
--- a/librender/Renderer_ogl.cpp        2010-07-31 16:32:49 +0000
+++ b/librender/Renderer_ogl.cpp        2010-08-03 19:10:44 +0000
@@ -23,8 +23,9 @@
 
 #include <cstring>
 #include <cmath>
+#include <boost/scoped_ptr.hpp>
 
-#include <smart_ptr.h>
+#include "smart_ptr.h"
 #include "swf/ShapeRecord.h"
 #include "gnash.h"
 #include "RGBA.h"
@@ -110,12 +111,71 @@
 namespace gnash {
 
 namespace {
-    const BitmapInfo* createGradientBitmap(const GradientFill& gf,
+    const CachedBitmap* createGradientBitmap(const GradientFill& gf,
             Renderer& renderer);
 }
 
 namespace {
 
+class bitmap_info_ogl : public CachedBitmap
+{
+public:
+  
+    /// Set line and fill styles for mesh & line_strip rendering.
+    enum bitmap_wrap_mode
+    {
+      WRAP_REPEAT,
+      WRAP_CLAMP
+    };
+
+    bitmap_info_ogl(std::auto_ptr<GnashImage> image, GLenum pixelformat,
+                    bool ogl_accessible);
+
+    ~bitmap_info_ogl();
+ 
+    /// TODO: implement this meaningfully.
+    virtual void dispose() {
+        _disposed = true;
+    }
+
+    virtual bool disposed() const {
+        return _disposed;
+    }
+
+    virtual GnashImage& image() {
+        if (_cache.get()) return *_cache;
+        switch (_pixel_format) {
+            case GL_RGB:
+                _cache.reset(new ImageRGB(_orig_width, _orig_height));
+                break;
+            case GL_RGBA:
+                _cache.reset(new ImageRGBA(_orig_width, _orig_height));
+                break;
+            default:
+                std::abort();
+        }
+        std::fill(_cache->begin(), _cache->end(), 0xff);
+        return *_cache;
+    }
+
+    void apply(const gnash::SWFMatrix& bitmap_matrix,
+               bitmap_wrap_mode wrap_mode) const;
+private:
+    inline bool ogl_accessible() const;
+    void setup() const;    
+    void upload(boost::uint8_t* data, size_t width, size_t height) const;
+    
+    mutable boost::scoped_ptr<GnashImage> _img;
+    mutable boost::scoped_ptr<GnashImage> _cache;
+    GLenum _pixel_format;
+    GLenum _ogl_img_type;
+    mutable bool _ogl_accessible;  
+    mutable GLuint _texture_id;
+    size_t _orig_width;
+    size_t _orig_height;
+    bool _disposed;
+};
+
 /// Style handler
 //
 /// Transfer FillStyles to the ogl renderer.
@@ -487,18 +547,18 @@
   return n % 2 == 0;
 }
 
-// Use the image class copy constructor; it's not important any more
-// what kind of image it is.
-bitmap_info_ogl::bitmap_info_ogl(GnashImage* image, GLenum pixelformat,
-                                 bool ogl_accessible)
+
+bitmap_info_ogl::bitmap_info_ogl(std::auto_ptr<GnashImage> image,
+        GLenum pixelformat, bool ogl_accessible)
 :
-  _img(image->clone()),
+  _img(image.release()),
   _pixel_format(pixelformat),
   _ogl_img_type(_img->height() == 1 ? GL_TEXTURE_1D : GL_TEXTURE_2D),
   _ogl_accessible(ogl_accessible),
   _texture_id(0),
   _orig_width(_img->width()),
-  _orig_height(_img->height())
+  _orig_height(_img->height()),
+  _disposed(false)
 {   
   if (!_ogl_accessible) {
     return;      
@@ -516,50 +576,50 @@
 void
 bitmap_info_ogl::setup() const
 {      
-  oglScopeEnable enabler(_ogl_img_type);
-  
-  glGenTextures(1, &_texture_id);
-  glBindTexture(_ogl_img_type, _texture_id);
-  
-  bool resize = false;
-  if (_img->height() == 1) {
-    if ( !isEven( _img->width() ) ) {
-      resize = true;
-    }
-  } else {
-    if (!isEven( _img->width() ) || !isEven(_img->height()) ) {
-      resize = true;
-    }     
-  }
-  
-  if (!resize) {
-    upload(_img->data(), _img->width(), _img->height());
-  } else {     
-    
-    size_t w = 1; while (w < _img->width()) { w <<= 1; }
-    size_t h = 1;
-    if (_img->height() != 1) {
-      while (h < _img->height()) { h <<= 1; }
-    }
-    
-    boost::scoped_array<boost::uint8_t> resized_data(new 
boost::uint8_t[w*h*_img->pixelSize()]);
-    // Q: Would mipmapping these textures aid in performance?
-    
-    GLint rv = gluScaleImage(_pixel_format, _img->width(),
-      _img->height(), GL_UNSIGNED_BYTE, _img->data(), w, h,
-      GL_UNSIGNED_BYTE, resized_data.get());
-    if (rv != 0) {
-      Tesselator::error(rv);
-      assert(0);
-    }
-    
-    upload(resized_data.get(), w, h);
-  }
-  
-  // _img (or a modified version thereof) has been uploaded to OpenGL. We
-  // no longer need to keep it around. Of course this goes against the
-  // principles of auto_ptr...
-  _img.reset();
+    oglScopeEnable enabler(_ogl_img_type);
+  
+    glGenTextures(1, &_texture_id);
+    glBindTexture(_ogl_img_type, _texture_id);
+  
+    bool resize = false;
+    if (_img->height() == 1) {
+        if (!isEven(_img->width())) {
+            resize = true;
+        }
+    } 
+    else {
+        if (!isEven(_img->width()) || !isEven(_img->height())) {
+            resize = true;
+        }     
+    }
+  
+    if (!resize) {
+        upload(_img->begin(), _img->width(), _img->height());
+    } 
+    else {     
+    
+        size_t w = 1; while (w < _img->width()) { w <<= 1; }
+        size_t h = 1;
+        if (_img->height() != 1) {
+            while (h < _img->height()) { h <<= 1; }
+        }
+    
+        boost::scoped_array<boost::uint8_t> resized_data(
+                new boost::uint8_t[w * h * _img->channels()]);
+        // Q: Would mipmapping these textures aid in performance?
+    
+        GLint rv = gluScaleImage(_pixel_format, _img->width(),
+                _img->height(), GL_UNSIGNED_BYTE, _img->begin(), w, h,
+                GL_UNSIGNED_BYTE, resized_data.get());
+        if (rv != 0) {
+            Tesselator::error(rv);
+            assert(0);
+        }
+    
+        upload(resized_data.get(), w, h);
+    }
+  
+    _img.reset();
 }
 
 void
@@ -584,6 +644,9 @@
 bitmap_info_ogl::apply(const gnash::SWFMatrix& bitmap_matrix,
                        bitmap_wrap_mode wrap_mode) const
 {
+    // TODO: use the altered data. Currently it doesn't display anything,
+    // so I don't feel obliged to implement this!
+
   glEnable(_ogl_img_type);
 
   glEnable(GL_TEXTURE_GEN_S);
@@ -718,14 +781,23 @@
 #endif
   }    
 
-  virtual BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im)
+  virtual CachedBitmap* createCachedBitmap(std::auto_ptr<GnashImage> im)
   {
-      switch (im->type())
-      {
+      switch (im->type()) {
           case GNASH_IMAGE_RGB:
-              return new bitmap_info_ogl(im.get(), GL_RGB, ogl_accessible());
+          {
+              std::auto_ptr<GnashImage> rgba(
+                      new ImageRGBA(im->width(), im->height()));
+
+              GnashImage::iterator it = rgba->begin();
+              for (size_t i = 0; i < im->size(); ++i) {
+                  *it++ = *(im->begin() + i);
+                  if (!(i % 3)) *it++ = 0xff;
+              }
+              im = rgba;
+          }
           case GNASH_IMAGE_RGBA:
-                return new bitmap_info_ogl(im.get(), GL_RGBA, 
ogl_accessible());
+                return new bitmap_info_ogl(im, GL_RGBA, ogl_accessible());
           default:
                 std::abort();
       }
@@ -827,7 +899,7 @@
 
     switch (frame->location()) {
     case GNASH_IMAGE_CPU:
-        texture->update(frame->data());
+        texture->update(frame->begin());
         break;
 #ifdef HAVE_VA_VA_GLX_H
     case GNASH_IMAGE_GPU:
@@ -1891,7 +1963,7 @@
     return fill.record(fill.recordCount() - 1).color;
 }
 
-const BitmapInfo*
+const CachedBitmap*
 createGradientBitmap(const GradientFill& gf, Renderer& renderer)
 {
     std::auto_ptr<ImageRGBA> im;
@@ -1936,7 +2008,7 @@
             break;
     }
 
-    const BitmapInfo* bi = renderer.createBitmapInfo(
+    const CachedBitmap* bi = renderer.createCachedBitmap(
                     static_cast<std::auto_ptr<GnashImage> >(im));
 
     return bi;

=== modified file 'librender/Renderer_ogl.h'
--- a/librender/Renderer_ogl.h  2010-03-14 21:23:43 +0000
+++ b/librender/Renderer_ogl.h  2010-08-03 18:58:27 +0000
@@ -52,7 +52,7 @@
 
 #include "Renderer.h"
 #include "Geometry.h"
-#include "BitmapInfo.h"
+#include "CachedBitmap.h"
 
 #include <map>
 
@@ -151,36 +151,6 @@
 };
 
 
-class bitmap_info_ogl : public BitmapInfo
-{
-  public:
-  
-    /// Set line and fill styles for mesh & line_strip rendering.
-    enum bitmap_wrap_mode
-    {
-      WRAP_REPEAT,
-      WRAP_CLAMP
-    };
-    
-    bitmap_info_ogl(GnashImage* image, GLenum pixelformat,
-                    bool ogl_accessible);
-    ~bitmap_info_ogl();
-
-    void apply(const gnash::SWFMatrix& bitmap_matrix,
-               bitmap_wrap_mode wrap_mode) const;
-  private:
-    inline bool ogl_accessible() const;
-    void setup() const;    
-    void upload(boost::uint8_t* data, size_t width, size_t height) const;
-    
-    mutable std::auto_ptr<GnashImage> _img;
-    GLenum _pixel_format;
-    GLenum _ogl_img_type;
-    mutable bool _ogl_accessible;  
-    mutable GLuint _texture_id;
-    size_t _orig_width;
-    size_t _orig_height;
-};
 
 
 DSOEXPORT Renderer* create_Renderer_ogl(bool init = true);
@@ -190,5 +160,5 @@
 } // namespace gnash
 
 
-#endif // __RENDER_HANDLER_OGL_H__
+#endif
 

=== modified file 'testsuite/MovieTester.cpp'
--- a/testsuite/MovieTester.cpp 2010-07-19 08:08:00 +0000
+++ b/testsuite/MovieTester.cpp 2010-08-03 16:40:04 +0000
@@ -160,7 +160,7 @@
     
     // This is a bit dangerous, as there isn't really support for swapping
     // renderers during runtime; though the only problem is likely to be
-    // that BitmapInfos are missing.
+    // that CachedBitmaps are missing.
     _runResources->setRenderer(h);
     
     h->set_invalidated_regions(invalidated_regions);

=== modified file 'testsuite/misc-ming.all/BeginBitmapFill.c'
--- a/testsuite/misc-ming.all/BeginBitmapFill.c 2010-07-28 07:27:26 +0000
+++ b/testsuite/misc-ming.all/BeginBitmapFill.c 2010-08-03 15:40:11 +0000
@@ -86,7 +86,7 @@
             "   lineTo(x + 100, y + 100);"
             "   lineTo(x + 0, y + 100);"
 
-            // Shape 2
+            // Shape 3
             "   x = 300;"
             "   y = 0;"
             "   moveTo(x + 0, y + 0);"
@@ -95,6 +95,7 @@
             "   lineTo(x + 0, y + 100);"
             "};"
             
+            // Shape 4
             "b = new flash.display.BitmapData(150, 150, false);"
             "b.fillRect(new flash.geom.Rectangle(10, 10, 10, 130), 0xff00ff);"
             "b.fillRect(new flash.geom.Rectangle(25, 10, 10, 130), 0xffff00);"
@@ -114,6 +115,7 @@
     
     /// Now with matrix argument. Repeat is true by default
     add_actions(mo,
+            // Shape 5
             "b = new flash.display.BitmapData(150, 150, false);"
             "b.fillRect(new flash.geom.Rectangle(10, 10, 10, 130), 0x000000);"
             "b.fillRect(new flash.geom.Rectangle(25, 10, 10, 130), 0xaaff00);"
@@ -134,6 +136,7 @@
 
     // Now with repeat set to false
     add_actions(mo,
+            // Shape 6
             "b = new flash.display.BitmapData(20, 20, false);"
             "b.fillRect(new flash.geom.Rectangle(0, 0, 10, 10), 0x000000);"
             "b.fillRect(new flash.geom.Rectangle(10, 10, 10, 10), 0xaaff00);"
@@ -153,6 +156,7 @@
             "   lineTo(x + 150, y + 0);"
             "};"
             
+            // Shape 7
             "mc = _root.createEmptyMovieClip('mc5', 99);"
             "with(mc) {"
             "   x = 500;"
@@ -170,6 +174,7 @@
 
     // Change the Bitmap afterwards
     add_actions(mo,
+            // Shape 8
             "b = new flash.display.BitmapData(20, 20, false);"
             "b.fillRect(new flash.geom.Rectangle(0, 0, 10, 10), 0x000000);"
             "b.fillRect(new flash.geom.Rectangle(10, 10, 10, 10), 0xaaff00);"
@@ -190,7 +195,33 @@
             "};"
             "b.fillRect(new flash.geom.Rectangle(0, 0, 20, 20), 0xff0000);"
             );
+    
+    // Dispose of the bitmap afterwards
+    add_actions(mo,
+            // Shape 9
+            "b = new flash.display.BitmapData(20, 20, false);"
+            "b.fillRect(new flash.geom.Rectangle(0, 0, 10, 10), 0x000000);"
+            "b.fillRect(new flash.geom.Rectangle(10, 10, 10, 10), 0xaaff00);"
+            "b.fillRect(new flash.geom.Rectangle(10, 0, 10, 10), 0xaaff00);"
+            "b.fillRect(new flash.geom.Rectangle(0, 10, 10, 10), 0xaaffaa);"
+            "mc = _root.createEmptyMovieClip('mc9', 222);"
+            "with(mc) {"
+            "   x = 450;"
+            "   y = 450;"
+            "   moveTo(x + 0, y + 0);"
+            "   m = new flash.geom.Matrix();"
+            "   m.tx = 0;"
+            "   m.ty = 450;"
+            "   beginBitmapFill(b, m, false);"
+            "   lineTo(x + 0, y + 100);"
+            "   lineTo(x + 150, y + 100);"
+            "   lineTo(x + 150, y + 0);"
+            "};"
+            "b.dispose();"
+            );
+    check_equals(mo, "_root.mc9._width", "150");
 
+    add_actions(mo, "stop();");
     SWFMovie_nextFrame(mo);
 
     //Output movie

=== modified file 'testsuite/misc-ming.all/BeginBitmapFillRunner.cpp'
--- a/testsuite/misc-ming.all/BeginBitmapFillRunner.cpp 2010-07-28 07:15:14 
+0000
+++ b/testsuite/misc-ming.all/BeginBitmapFillRunner.cpp 2010-08-04 06:03:53 
+0000
@@ -45,6 +45,7 @@
     MovieClip* root = tester.getRootMovie();
     assert(root);
 
+    const rgba black(0, 0, 0, 255);
     const rgba white(255, 255, 255, 255);
     const rgba blue(0, 0, 255, 255);
     const rgba cyan(0, 255, 255, 255);
@@ -52,12 +53,118 @@
     const rgba yellow(255, 255, 0, 255);
     const rgba magenta(255, 0, 255, 255);
     const rgba red(255, 0, 0, 255);
+    const rgba lightgreen(0xaa, 0xff, 0x00, 0xff);
+    const rgba funnycyan(0x00, 0xcc, 0xff, 0xff);
+    const rgba lightcyan(0xaa, 0xff, 0xaa, 0xff);
     
-    // Only one frame 
     tester.advance();
-    check_pixel(1, 1, 1, white, 8);
-
-    // TODO: add real tests!
+    check_pixel(1, 1, 1, white, 2);
+
+    // Shape 1
+    // Red stripe
+    check_pixel(15, 15, 1, red, 2);
+    check_pixel(15, 85, 1, red, 2);
+    // Green stripe
+    check_pixel(30, 15, 1, green, 2);
+    check_pixel(30, 85, 1, green, 2);
+    // Blue
+    check_pixel(45, 15, 1, blue, 2);
+    check_pixel(45, 85, 1, blue, 2);
+    
+    // Shape 2
+    // Red stripe
+    check_pixel(165, 15, 1, red, 2);
+    check_pixel(165, 85, 1, red, 2);
+    // Green stripe
+    check_pixel(180, 15, 1, green, 2);
+    check_pixel(180, 85, 1, green, 2);
+    // Blue
+    check_pixel(195, 15, 1, blue, 2);
+    // Cut due to the shape.
+    check_pixel(195, 87, 1, white, 2);
+    
+    // Shape 3
+    // Red stripe
+    check_pixel(315, 14, 1, white, 2);
+    check_pixel(315, 85, 1, red, 2);
+    // Green stripe
+    check_pixel(330, 15, 1, white, 2);
+    check_pixel(330, 85, 1, green, 2);
+    // Blue
+    check_pixel(345, 15, 1, white, 2);
+    // Cut due to the shape.
+    check_pixel(345, 85, 1, blue, 2);
+
+    // Shape 4
+    // Skewed, scaled shape.
+    check_pixel(100, 200, 1, magenta, 2);
+    check_pixel(150, 200, 1, yellow, 2);
+    check_pixel(230, 200, 1, cyan, 2);
+    check_pixel(235, 250, 1, magenta, 2);
+    check_pixel(315, 250, 1, yellow, 2);
+    check_pixel(395, 250, 1, white, 2);
+
+    // Shape 5
+    check_pixel(30, 315, 1, black, 2);
+    check_pixel(70, 315, 1, black, 2);
+    check_pixel(140, 315, 1, white, 2);
+    check_pixel(170, 315, 1, black, 2);
+    check_pixel(30, 330, 1, lightgreen, 2);
+    check_pixel(70, 330, 1, lightgreen, 2);
+    check_pixel(140, 330, 1, white, 2);
+    check_pixel(170, 330, 1, lightgreen, 2);
+    check_pixel(30, 345, 1, funnycyan, 2);
+    check_pixel(70, 345, 1, funnycyan, 2);
+    check_pixel(140, 345, 1, white, 2);
+    check_pixel(170, 345, 1, funnycyan, 2);
+
+    // Shape 6
+    // Edge pixels extend to edge of shape
+    // Top left
+    check_pixel(298, 298, 1, white, 2);
+    check_pixel(302, 302, 1, black, 2);
+    // Centre of fill
+    check_pixel(352, 352, 1, black, 2);
+    check_pixel(352, 362, 1, lightcyan, 2);
+    check_pixel(362, 362, 1, lightgreen, 2);
+    // Bottom left
+    check_pixel(302, 398, 1, lightcyan, 2);
+    check_pixel(298, 398, 1, white, 2);
+    // Bottom right
+    check_pixel(448, 398, 1, lightgreen, 2);
+    check_pixel(448, 402, 1, white, 2);
+
+    // Shape 7: tiled 20x20 blocks centred at (550, 550)
+    check_pixel(498, 298, 1, white, 2);
+    check_pixel(552, 352, 1, black, 2);
+    check_pixel(552, 362, 1, lightcyan, 2);
+    check_pixel(562, 362, 1, lightgreen, 2);
+    // 20 right
+    check_pixel(572, 352, 1, black, 2);
+    check_pixel(572, 362, 1, lightcyan, 2);
+    check_pixel(582, 362, 1, lightgreen, 2);
+    // 20 down
+    check_pixel(552, 372, 1, black, 2);
+    check_pixel(552, 382, 1, lightcyan, 2);
+    check_pixel(562, 382, 1, lightgreen, 2);
+    // 20 right and down
+    check_pixel(572, 372, 1, black, 2);
+    check_pixel(572, 382, 1, lightcyan, 2);
+    check_pixel(582, 382, 1, lightgreen, 2);
+    // Some random blocks.
+    check_pixel(512, 312, 1, black, 2);
+    check_pixel(532, 382, 1, lightcyan, 2);
+    check_pixel(522, 362, 1, lightgreen, 2);
+    
+    // Shape 8
+    // This should change with the BitmapData.
+    check_pixel(20, 465, 1, red, 2);
+    
+    // Shape 9
+    // This should not display because the BitmapData is disposed.
+    check_pixel(460, 460, 1, white, 2);
+    check_pixel(500, 460, 1, white, 2);
+    check_pixel(460, 500, 1, white, 2);
 
 }
 


reply via email to

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