gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash/server Makefile.am impl.cpp impl.h Movie....


From: strk
Subject: [Gnash-commit] gnash/server Makefile.am impl.cpp impl.h Movie....
Date: Wed, 25 Jan 2006 18:03:25 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Branch:         
Changes by:     strk <address@hidden>   06/01/25 18:03:25

Modified files:
        server         : Makefile.am impl.cpp impl.h 
Added files:
        server         : Movie.cpp Movie.h Sprite.cpp Sprite.h 

Log message:
        Extracted Movie and Sprite classes from impl.
        Still a lot to be done to clean them up, but at least
        they are in a separate file now.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Makefile.am.diff?tr1=1.11&tr2=1.12&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Movie.cpp?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Movie.h?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Sprite.cpp?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Sprite.h?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/impl.cpp.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/impl.h.diff?tr1=1.3&tr2=1.4&r1=text&r2=text

Patches:
Index: gnash/server/Makefile.am
diff -u gnash/server/Makefile.am:1.11 gnash/server/Makefile.am:1.12
--- gnash/server/Makefile.am:1.11       Tue Jan 24 10:12:00 2006
+++ gnash/server/Makefile.am    Wed Jan 25 18:03:25 2006
@@ -58,9 +58,11 @@
         impl.cpp         \
         log.cpp          \
         morph2.cpp       \
+       Movie.cpp        \
         render.cpp       \
         shape.cpp        \
         sound.cpp        \
+       Sprite.cpp       \
         stream.cpp       \
         styles.cpp       \
         tesselate.cpp    \
@@ -80,12 +82,14 @@
        log.h           \
        morph2.h        \
        morph.h         \
+       Movie.h         \
        MovieClipLoader.h       \
        render.h        \
        shape.h         \
        sound.h         \
        stream.h        \
        gstring.h       \
+       Sprite.h        \
        styles.h        \
        tesselate.h     \
        textformat.h    \
Index: gnash/server/impl.cpp
diff -u gnash/server/impl.cpp:1.7 gnash/server/impl.cpp:1.8
--- gnash/server/impl.cpp:1.7   Tue Jan 24 01:33:02 2006
+++ gnash/server/impl.cpp       Wed Jan 25 18:03:25 2006
@@ -38,6 +38,8 @@
 #include "image.h"
 #include "jpeg.h"
 #include "zlib_adapter.h"
+#include "Sprite.h"
+#include "Movie.h"
 #include <string.h>    // for memset
 #include <typeinfo>
 #include <float.h>
@@ -85,7 +87,7 @@
 }
 
 // Keep a table of loader functions for the different tag types.
-static hash<int, loader_function>      s_tag_loaders;
+hash<int, loader_function>     s_tag_loaders;
 
     // Associate the specified tag type with the given tag loader
     // function.
@@ -112,76 +114,6 @@
     s_opener_function = opener;
 }
 
-//
-// progress callback stuff (from Vitaly)
-//
-
-static progress_callback       s_progress_function = NULL;
-
-// Host calls this to register a function for progress bar handling
-// during loading movies.
-void
-register_progress_callback(progress_callback progress_handle)
-{
-    s_progress_function = progress_handle;
-}
-
-//
-// some utility stuff
-//
-static void
-execute_actions(as_environment* env, const array<action_buffer*>& action_list)
-    // Execute the actions in the action list, in the given
-    // environment.
-{
-    for (int i = 0; i < action_list.size(); i++)
-       {
-           action_list[i]->execute(env);
-       }
-}
-
-
-static void    dump_tag_bytes(stream* in)
-    // Log the contents of the current tag, in hex.
-{
-    static const int   ROW_BYTES = 16;
-    char       row_buf[ROW_BYTES];
-    int        row_count = 0;
-
-    while(in->get_position() < in->get_tag_end_position())
-       {
-           int c = in->read_u8();
-           log_msg("%02X", c);
-
-           if (c < 32) c = '.';
-           if (c > 127) c = '.';
-           row_buf[row_count] = c;
-                       
-           row_count++;
-           if (row_count >= ROW_BYTES)
-               {
-                   log_msg("    ");
-                   for (int i = 0; i < ROW_BYTES; i++)
-                       {
-                           log_msg("%c", row_buf[i]);
-                       }
-
-                   log_msg("\n");
-                   row_count = 0;
-               }
-           else
-               {
-                   log_msg(" ");
-               }
-       }
-
-    if (row_count > 0)
-       {
-           log_msg("\n");
-       }
-}
-
-
 character*     character_def::create_character_instance(movie* parent, int id)
     // Default.  Make a generic_character.
 {
@@ -301,4302 +233,1523 @@
        }
 }
 
-
-//
-// Helper for movie_def_impl
-//
-
-struct import_info
+static void    ensure_loaders_registered()
 {
-    tu_string  m_source_url;
-    int                m_character_id;
-    tu_string  m_symbol;
-
-    import_info()
-       :
-       m_character_id(-1)
-       {
-       }
-
-    import_info(const char* source, int id, const char* symbol)
-       :
-       m_source_url(source),
-       m_character_id(id),
-       m_symbol(symbol)
+    static bool        s_registered = false;
+       
+    if (s_registered == false)
        {
+           // Register the standard loaders.
+           s_registered = true;
+           register_tag_loader(0, end_loader);
+           register_tag_loader(2, define_shape_loader);
+           register_tag_loader(4, place_object_2_loader);
+           register_tag_loader(5, remove_object_2_loader);
+           register_tag_loader(6, define_bits_jpeg_loader);
+           register_tag_loader(7, button_character_loader);
+           register_tag_loader(8, jpeg_tables_loader);
+           register_tag_loader(9, set_background_color_loader);
+           register_tag_loader(10, define_font_loader);
+           register_tag_loader(11, define_text_loader);
+           register_tag_loader(12, do_action_loader);
+           register_tag_loader(13, define_font_info_loader);
+           register_tag_loader(14, define_sound_loader);
+           register_tag_loader(15, start_sound_loader);
+           register_tag_loader(17, button_sound_loader);
+           register_tag_loader(20, define_bits_lossless_2_loader);
+           register_tag_loader(21, define_bits_jpeg2_loader);
+           register_tag_loader(22, define_shape_loader);
+           register_tag_loader(24, null_loader);       // "protect" tag; we're 
not an authoring tool so we don't care.
+           register_tag_loader(26, place_object_2_loader);
+           register_tag_loader(28, remove_object_2_loader);
+           register_tag_loader(32, define_shape_loader);
+           register_tag_loader(33, define_text_loader);
+           register_tag_loader(37, define_edit_text_loader);
+           register_tag_loader(34, button_character_loader);
+           register_tag_loader(35, define_bits_jpeg3_loader);
+           register_tag_loader(36, define_bits_lossless_2_loader);
+           register_tag_loader(39, sprite_loader);
+           register_tag_loader(43, frame_label_loader);
+           register_tag_loader(46, define_shape_morph_loader);
+           register_tag_loader(48, define_font_loader);
+           register_tag_loader(56, export_loader);
+           register_tag_loader(57, import_loader);
+           register_tag_loader(59, do_init_action_loader);   
        }
-};
-
+}
 
-//
-// movie_def_impl
-//
-// This class holds the immutable definition of a movie's
-// contents.  It cannot be played directly, and does not hold
-// current state; for that you need to call create_instance()
-// to get a movie_instance.
-//
 
 
-struct movie_def_impl : public movie_definition_sub
+void   get_movie_info(
+    const char* filename,
+    int* version,
+    int* width,
+    int* height,
+    float* frames_per_second,
+    int* frame_count,
+    int* tag_count
+    )
+    // Attempt to read the header of the given .swf movie file.
+    // Put extracted info in the given vars.
+    // Sets *version to 0 if info can't be extracted.
 {
-    hash<int, smart_ptr<character_def> >       m_characters;
-    hash<int, smart_ptr<font> >         m_fonts;
-    hash<int, smart_ptr<bitmap_character_def> >        m_bitmap_characters;
-    hash<int, smart_ptr<sound_sample> >        m_sound_samples;
-    array<array<execute_tag*> >           m_playlist;  // A list of movie 
control events for each frame.
-    array<array<execute_tag*> >           m_init_action_list;  // Init actions 
for each frame.
-    stringi_hash<int>             m_named_frames;      // 0-based frame #'s
-    stringi_hash<smart_ptr<resource> > m_exports;
-
-    // Items we import.
-    array<import_info> m_imports;
-
-    // Movies we import from; hold a ref on these, to keep them alive
-    array<smart_ptr<movie_definition> >        m_import_source_movies;
-
-    // Bitmaps used in this movie; collected in one place to make
-    // it possible for the host to manage them as textures.
-    array<smart_ptr<bitmap_info> >     m_bitmap_list;
-
-    create_bitmaps_flag        m_create_bitmaps;
-    create_font_shapes_flag    m_create_font_shapes;
-
-    rect       m_frame_size;
-    float      m_frame_rate;
-    int        m_frame_count;
-    int        m_version;
-    int        m_loading_frame;
-    uint32     m_file_length;
+    if (s_opener_function == NULL)
+       {
+           log_error("error: get_movie_info(): no file opener function 
registered\n");
+           if (version) *version = 0;
+           return;
+       }
 
-    jpeg::input*       m_jpeg_in;
+    tu_file*   in = s_opener_function(filename);
+    if (in == NULL || in->get_error() != TU_FILE_NO_ERROR)
+       {
+           log_error("error: get_movie_info(): can't open '%s'\n", filename);
+           if (version) *version = 0;
+           delete in;
+           return;
+       }
 
+    Uint32     file_start_pos = in->get_position();
+    Uint32     header = in->read_le32();
+    Uint32     file_length = in->read_le32();
+    Uint32     file_end_pos = file_start_pos + file_length;
 
-    movie_def_impl(create_bitmaps_flag cbf, create_font_shapes_flag cfs)
-       :
-       m_create_bitmaps(cbf),
-       m_create_font_shapes(cfs),
-       m_frame_rate(30.0f),
-       m_frame_count(0),
-       m_version(0),
-       m_loading_frame(0),
-       m_jpeg_in(0)
+    int        local_version = (header >> 24) & 255;
+    if ((header & 0x0FFFFFF) != 0x00535746
+       && (header & 0x0FFFFFF) != 0x00535743)
        {
+           // ERROR
+           log_error("error: get_movie_info(): file '%s' does not start with a 
SWF header!\n", filename);
+           if (version) *version = 0;
+           delete in;
+           return;
        }
+    bool       compressed = (header & 255) == 'C';
 
-    ~movie_def_impl()
+    tu_file*   original_in = NULL;
+    if (compressed)
        {
-           // Release our playlist data.
-           {for (int i = 0, n = m_playlist.size(); i < n; i++)
-               {
-                   for (int j = 0, m = m_playlist[i].size(); j < m; j++)
-                       {
-                           delete m_playlist[i][j];
-                       }
-               }}
+#if TU_CONFIG_LINK_TO_ZLIB == 0
+           log_error("get_movie_info(): can't read zipped SWF data; 
TU_CONFIG_LINK_TO_ZLIB is 0!\n");
+           return;
+#endif
+           original_in = in;
 
-           // Release init action data.
-           {for (int i = 0, n = m_init_action_list.size(); i < n; i++)
-               {
-                   for (int j = 0, m = m_init_action_list[i].size(); j < m; 
j++)
-                       {
-                           delete m_init_action_list[i][j];
-                       }
-               }}
+           // Uncompress the input as we read it.
+           in = zlib_adapter::make_inflater(original_in);
 
-           assert(m_jpeg_in == NULL);  // It's supposed to be cleaned up in 
read()
+           // Subtract the size of the 8-byte header, since
+           // it's not included in the compressed
+           // stream length.
+           file_length -= 8;
        }
 
+    stream     str(in);
 
-    movie_interface*   create_instance();
-
-    // ...
-    int        get_frame_count() const { return m_frame_count; }
-    float      get_frame_rate() const { return m_frame_rate; }
-    float      get_width_pixels() const { return 
ceilf(TWIPS_TO_PIXELS(m_frame_size.width())); }
-    float      get_height_pixels() const { return 
ceilf(TWIPS_TO_PIXELS(m_frame_size.height())); }
-
-    virtual int        get_version() const { return m_version; }
+    rect       frame_size;
+    frame_size.read(&str);
 
-    virtual int        get_loading_frame() const { return m_loading_frame; }
+    float      local_frame_rate = str.read_u16() / 256.0f;
+    int        local_frame_count = str.read_u16();
 
-    uint32     get_file_bytes() const { return m_file_length; }
+    if (version) *version = local_version;
+    if (width) *width = int(frame_size.width() / 20.0f + 0.5f);
+    if (height) *height = int(frame_size.height() / 20.0f + 0.5f);
+    if (frames_per_second) *frames_per_second = local_frame_rate;
+    if (frame_count) *frame_count = local_frame_count;
 
-    /* movie_def_impl */
-    virtual create_bitmaps_flag        get_create_bitmaps() const
-       // Returns DO_CREATE_BITMAPS if we're supposed to
-       // initialize our bitmap infos, or DO_NOT_INIT_BITMAPS
-       // if we're supposed to create blank placeholder
-       // bitmaps (to be init'd later explicitly by the host
-       // program).
+    if (tag_count)
        {
-           return m_create_bitmaps;
+           // Count tags.
+           int local_tag_count = 0;
+           while ((Uint32) str.get_position() < file_end_pos)
+               {
+                   str.open_tag();
+                   str.close_tag();
+                   local_tag_count++;
+               }
+           *tag_count = local_tag_count;
        }
 
-    /* movie_def_impl */
-    virtual create_font_shapes_flag    get_create_font_shapes() const
-       // Returns DO_LOAD_FONT_SHAPES if we're supposed to
-       // initialize our font shape info, or
-       // DO_NOT_LOAD_FONT_SHAPES if we're supposed to not
-       // create any (vector) font glyph shapes, and instead
-       // rely on precached textured fonts glyphs.
-       {
-           return m_create_font_shapes;
-       }
+    delete in;
+    delete original_in;
+}
 
-    virtual void       add_bitmap_info(bitmap_info* bi)
-       // All bitmap_info's used by this movie should be
-       // registered with this API.
-       {
-           m_bitmap_list.push_back(bi);
-       }
 
 
-    virtual int        get_bitmap_info_count() const { return 
m_bitmap_list.size(); }
-    virtual bitmap_info*       get_bitmap_info(int i) const
+movie_definition*      create_movie(const char* filename)
+    // Create the movie definition from the specified .swf file.
+{
+    return create_movie_sub(filename);
+}
+
+
+movie_definition_sub*  create_movie_sub(const char* filename)
+{
+    printf("%s: filename is %s\n",  __PRETTY_FUNCTION__, filename);
+    if (s_opener_function == NULL)
        {
-           return m_bitmap_list[i].get_ptr();
+           // Don't even have a way to open the file.
+           log_error("error: no file opener function; can't create movie.  "
+                     "See gnash::register_file_opener_callback\n");
+           return NULL;
        }
 
-    virtual void       export_resource(const tu_string& symbol, resource* res)
-       // Expose one of our resources under the given symbol,
-       // for export.  Other movies can import it.
+    tu_file* in = s_opener_function(filename);
+    if (in == NULL)
        {
-           // SWF sometimes exports the same thing more than once!
-           m_exports.set(symbol, res);
+           log_error("failed to open '%s'; can't create movie.\n", filename);
+           return NULL;
        }
-
-    virtual smart_ptr<resource>        get_exported_resource(const tu_string& 
symbol)
-       // Get the named exported resource, if we expose it.
-       // Otherwise return NULL.
+    else if (in->get_error())
        {
-           smart_ptr<resource> res;
-           m_exports.get(symbol, &res);
-           return res;
+           log_error("error: file opener can't open '%s'\n", filename);
+           return NULL;
        }
 
-    virtual void       add_import(const char* source_url, int id, const char* 
symbol)
-       // Adds an entry to a table of resources that need to
-       // be imported from other movies.  Client code must
-       // call resolve_import() later, when the source movie
-       // has been loaded, so that the actual resource can be
-       // used.
-       {
-           assert(in_import_table(id) == false);
+    ensure_loaders_registered();
 
-           m_imports.push_back(import_info(source_url, id, symbol));
-       }
+    movie_def_impl*    m = new movie_def_impl(DO_LOAD_BITMAPS, 
DO_LOAD_FONT_SHAPES);
+    m->read(in);
 
-    bool       in_import_table(int character_id)
-       // Debug helper; returns true if the given
-       // character_id is listed in the import table.
-       {
-           for (int i = 0, n = m_imports.size(); i < n; i++)
-               {
-                   if (m_imports[i].m_character_id == character_id)
-                       {
-                           return true;
-                       }
-               }
-           return false;
-       }
+    delete in;
 
-    virtual void       visit_imported_movies(import_visitor* visitor)
-       // Calls back the visitor for each movie that we
-       // import symbols from.
+    if (m && s_use_cache_files)
        {
-           stringi_hash<bool>  visited;        // ugh!
+           // Try to load a .gsc file.
+           tu_string   cache_filename(filename);
+           cache_filename += ".gsc";
+           tu_file*    cache_in = s_opener_function(cache_filename.c_str());
+           if (cache_in == NULL
+               || cache_in->get_error() != TU_FILE_NO_ERROR)
+               {
+                   // Can't open cache file; don't sweat it.
+                   IF_VERBOSE_PARSE(log_msg("note: couldn't open cache file 
'%s'\n", cache_filename.c_str()));
 
-           for (int i = 0, n = m_imports.size(); i < n; i++)
+                   m->generate_font_bitmaps(); // can't read cache, so 
generate font texture data.
+               }
+           else
                {
-                   import_info&        inf = m_imports[i];
-                   if (visited.find(inf.m_source_url) == visited.end())
-                       {
-                           // Call back the visitor.
-                           visitor->visit(inf.m_source_url.c_str());
-                           visited.set(inf.m_source_url, true);
-                       }
+                   // Load the cached data.
+                   m->input_cached_data(cache_in);
                }
+
+           delete cache_in;
        }
 
-    virtual void       resolve_import(const char* source_url, 
movie_definition* source_movie)
-       // Grabs the stuff we want from the source movie.
-       {
-           // @@ should be safe, but how can we verify
-           // it?  Compare a member function pointer, or
-           // something?
-           movie_def_impl*     def_impl = 
static_cast<movie_def_impl*>(source_movie);
-           movie_definition_sub*       def = 
static_cast<movie_definition_sub*>(def_impl);
+    m->add_ref();
+    return m;
+}
 
-           // Iterate in reverse, since we remove stuff along the way.
-           for (int i = m_imports.size() - 1; i >= 0; i--)
-               {
-                   const import_info&  inf = m_imports[i];
-                   if (inf.m_source_url == source_url)
-                       {
-                           // Do the import.
-                           smart_ptr<resource> res = 
def->get_exported_resource(inf.m_symbol);
-                           bool         imported = true;
 
-                           if (res == NULL)
-                               {
-                                   log_error("import error: resource '%s' is 
not exported from movie '%s'\n",
-                                             inf.m_symbol.c_str(), source_url);
-                               }
-                           else if (font* f = res->cast_to_font())
-                               {
-                                   // Add this shared font to our fonts.
-                                   add_font(inf.m_character_id, f);
-                                   imported = true;
-                               }
-                           else if (character_def* ch = 
res->cast_to_character_def())
-                               {
-                                   // Add this character to our characters.
-                                   add_character(inf.m_character_id, ch);
-                                   imported = true;
-                               }
-                           else
-                               {
-                                   log_error("import error: resource '%s' from 
movie '%s' has unknown type\n",
-                                             inf.m_symbol.c_str(), source_url);
-                               }
+static bool    s_no_recurse_while_loading = false;     // @@ TODO get rid of 
this; make it the normal mode.
 
-                           if (imported)
-                               {
-                                   m_imports.remove(i);
 
-                                   // Hold a ref, to keep this source 
movie_definition alive.
-                                   
m_import_source_movies.push_back(source_movie);
-                               }
-                       }
-               }
-       }
-
-    void       add_character(int character_id, character_def* c)
-       {
-           assert(c);
-           m_characters.add(character_id, c);
-       }
-
-    character_def*     get_character_def(int character_id)
-       {
-#ifndef NDEBUG
-           // make sure character_id is resolved
-           if (in_import_table(character_id))
-               {
-                   log_error("get_character_def(): character_id %d is still 
waiting to be imported\n",
-                             character_id);
-               }
-#endif // not NDEBUG
-
-           smart_ptr<character_def>    ch;
-           m_characters.get(character_id, &ch);
-           assert(ch == NULL || ch->get_ref_count() > 1);
-           return ch.get_ptr();
-       }
-
-    bool       get_labeled_frame(const char* label, int* frame_number)
-       // Returns 0-based frame #
-       {
-           return m_named_frames.get(label, frame_number);
-       }
-
-    void       add_font(int font_id, font* f)
-       {
-           assert(f);
-           m_fonts.add(font_id, f);
-       }
-
-    font*      get_font(int font_id)
-       {
-#ifndef NDEBUG
-           // make sure font_id is resolved
-           if (in_import_table(font_id))
-               {
-                   log_error("get_font(): font_id %d is still waiting to be 
imported\n",
-                             font_id);
-               }
-#endif // not NDEBUG
+movie_definition*      create_movie_no_recurse(
+    tu_file* in,
+    create_bitmaps_flag cbf,
+    create_font_shapes_flag cfs)
+{
+    ensure_loaders_registered();
 
-           smart_ptr<font>     f;
-           m_fonts.get(font_id, &f);
-           assert(f == NULL || f->get_ref_count() > 1);
-           return f.get_ptr();
-       }
+    // @@ TODO make no_recurse the standard way to load.
+    // In create_movie(), use the visit_ API to keep
+    // visiting dependent movies, until everything is
+    // loaded.  That way we only have one code path and
+    // the resource_proxy stuff gets tested.
+    s_no_recurse_while_loading = true;
 
-    bitmap_character_def*      get_bitmap_character(int character_id)
-       {
-           smart_ptr<bitmap_character_def>     ch;
-           m_bitmap_characters.get(character_id, &ch);
-           assert(ch == NULL || ch->get_ref_count() > 1);
-           return ch.get_ptr();
-       }
+    movie_def_impl*    m = new movie_def_impl(cbf, cfs);
+    m->read(in);
 
-    void       add_bitmap_character(int character_id, bitmap_character_def* ch)
-       {
-           assert(ch);
-           m_bitmap_characters.add(character_id, ch);
+    s_no_recurse_while_loading = false;
 
-           add_bitmap_info(ch->get_bitmap_info());
-       }
+    m->add_ref();
+    return m;
+}
 
-    sound_sample*      get_sound_sample(int character_id)
-       {
-           smart_ptr<sound_sample>     ch;
-           m_sound_samples.get(character_id, &ch);
-           assert(ch == NULL || ch->get_ref_count() > 1);
-           return ch.get_ptr();
-       }
 
-    virtual void       add_sound_sample(int character_id, sound_sample* sam)
-       {
-           assert(sam);
-           m_sound_samples.add(character_id, sam);
-       }
+//
+// global gnash management
+//
 
-    void       add_execute_tag(execute_tag* e)
-       {
-           assert(e);
-           m_playlist[m_loading_frame].push_back(e);
-       }
 
-    void       add_init_action(int sprite_id, execute_tag* e)
-       // Need to execute the given tag before entering the
-       // currently-loading frame for the first time.
-       //
-       // @@ AFAIK, the sprite_id is totally pointless -- correct?
-       {
-           assert(e);
-           m_init_action_list[m_loading_frame].push_back(e);
-       }
 
-    void       add_frame_name(const char* name)
-       // Labels the frame currently being loaded with the
-       // given name.  A copy of the name string is made and
-       // kept in this object.
-       {
-           assert(m_loading_frame >= 0 && m_loading_frame < m_frame_count);
+void   clear()
+    // Maximum release of resources.
+{
+    clear_library();
+    fontlib::clear();
+    action_clear();
+}
 
-           tu_string   n = name;
-           assert(m_named_frames.get(n, NULL) == false);       // frame should 
not already have a name (?)
-           m_named_frames.add(n, m_loading_frame);     // stores 0-based frame 
#
-       }
 
-    void       set_jpeg_loader(jpeg::input* j_in)
-       // Set an input object for later loading DefineBits
-       // images (JPEG images without the table info).
-       {
-           assert(m_jpeg_in == NULL);
-           m_jpeg_in = j_in;
-       }
+//
+// library stuff, for sharing resources among different movies.
+//
 
-    jpeg::input*       get_jpeg_loader()
-       // Get the jpeg input loader, to load a DefineBits
-       // image (one without table info).
-       {
-           return m_jpeg_in;
-       }
 
+static stringi_hash< smart_ptr<movie_definition_sub> > s_movie_library;
+static hash< movie_definition_sub*, smart_ptr<movie_interface> >       
s_movie_library_inst;
+static array<movie_interface*> s_extern_sprites;
+static movie_interface* s_current_root;
 
-    virtual const array<execute_tag*>& get_playlist(int frame_number) { return 
m_playlist[frame_number]; }
+static tu_string s_workdir;
 
-    /* movie_def_impl */
-    virtual const array<execute_tag*>* get_init_actions(int frame_number)
-       {
-           return &m_init_action_list[frame_number];
-       }
+void save_extern_movie(movie_interface* m)
+{
+    s_extern_sprites.push_back(m);
+}
 
-    /* movie_def_impl */
-    void       read(tu_file* in)
-       // Read a .SWF movie.
+//#if 0
+void delete_unused_root()
+{
+    for (int i = 0; i < s_extern_sprites.size(); i++)
        {
-           Uint32      file_start_pos = in->get_position();
-           Uint32      header = in->read_le32();
-           m_file_length = in->read_le32();
-           Uint32      file_end_pos = file_start_pos + m_file_length;
-
-           m_version = (header >> 24) & 255;
-           if ((header & 0x0FFFFFF) != 0x00535746
-               && (header & 0x0FFFFFF) != 0x00535743)
-               {
-                   // ERROR
-                   log_error("gnash::movie_def_impl::read() -- file does not 
start with a SWF header!\n");
-                   return;
-               }
-           bool        compressed = (header & 255) == 'C';
-
-           IF_VERBOSE_PARSE(log_msg("version = %d, file_length = %d\n", 
m_version, m_file_length));
-
-           tu_file*    original_in = NULL;
-           if (compressed)
+           movie_interface* root_m = s_extern_sprites[i];
+           movie* m = root_m->get_root_movie();
+      
+           if (m->get_ref_count() < 2)
                {
-#if TU_CONFIG_LINK_TO_ZLIB == 0
-                   log_error("movie_def_impl::read(): unable to read zipped 
SWF data; TU_CONFIG_LINK_TO_ZLIB is 0\n");
-                   return;
-#endif
-
-                   IF_VERBOSE_PARSE(log_msg("file is compressed.\n"));
-                   original_in = in;
-
-                   // Uncompress the input as we read it.
-                   in = zlib_adapter::make_inflater(original_in);
-
-                   // Subtract the size of the 8-byte header, since
-                   // it's not included in the compressed
-                   // stream length.
-                   file_end_pos = m_file_length - 8;
+                   IF_VERBOSE_ACTION(log_msg("extern movie deleted\n"));
+                   s_extern_sprites.remove(i);
+                   i--;
+                   root_m->drop_ref();
                }
+       }
+}
+//#endif // 0
 
-           stream      str(in);
-
-           m_frame_size.read(&str);
-           m_frame_rate = str.read_u16() / 256.0f;
-           m_frame_count = str.read_u16();
-
-           m_playlist.resize(m_frame_count);
-           m_init_action_list.resize(m_frame_count);
-
-           IF_VERBOSE_PARSE(m_frame_size.print());
-           IF_VERBOSE_PARSE(log_msg("frame rate = %f, frames = %d\n", 
m_frame_rate, m_frame_count));
+movie_interface* get_current_root()
+{
+    assert(s_current_root != NULL);
+    return s_current_root;
+}
 
-           while ((Uint32) str.get_position() < file_end_pos)
-               {
-                   int tag_type = str.open_tag();
+void set_current_root(movie_interface* m)
+{
+    assert(m != NULL);
+    s_current_root = m;
+}
 
-                   if (s_progress_function != NULL)
-                       {
-                           s_progress_function((Uint32) str.get_position(), 
file_end_pos);
-                       }
+const char* get_workdir()
+{
+    return s_workdir.c_str();
+}
 
-                   loader_function     lf = NULL;
-                   //IF_VERBOSE_PARSE(log_msg("tag_type = %d\n", tag_type));
-                   if (tag_type == 1)
-                       {
-                           // show frame tag -- advance to the next frame.
-                           IF_VERBOSE_PARSE(log_msg("  show_frame\n"));
-                           m_loading_frame++;
-                       }
-                   else if (s_tag_loaders.get(tag_type, &lf))
-                       {
-                           // call the tag loader.  The tag loader should add
-                           // characters or tags to the movie data structure.
-                           (*lf)(&str, tag_type, this);
-
-                       } else {
-                           // no tag loader for this tag type.
-                           IF_VERBOSE_PARSE(log_msg("*** no tag loader for 
type %d\n", tag_type));
-                           IF_VERBOSE_PARSE(dump_tag_bytes(&str));
-                       }
+void set_workdir(const char* dir)
+{
+    assert(dir != NULL);
+    s_workdir = dir;
+}
 
-                   str.close_tag();
+void   clear_library()
+    // Drop all library references to movie_definitions, so they
+    // can be cleaned up.
+{
+    s_movie_library.clear();
+    s_movie_library_inst.clear();
+}
 
-                   if (tag_type == 0)
-                       {
-                           if ((unsigned int) str.get_position() != 
file_end_pos)
-                               {
-                                   // Safety break, so we don't read past the 
end of the
-                                   // movie.
-                                   log_msg("warning: hit stream-end tag, but 
not at the "
-                                           "end of the file yet; stopping for 
safety\n");
-                                   break;
-                               }
-                       }
-               }
+movie_definition*      create_library_movie(const char* filename)
+    // Try to load a movie from the given url, if we haven't
+    // loaded it already.  Add it to our library on success, and
+    // return a pointer to it.
+{
+    return create_library_movie_sub(filename);
+}
 
-           if (m_jpeg_in)
-               {
-                   delete m_jpeg_in;
-                   m_jpeg_in = NULL;
-               }
 
-           if (original_in)
-               {
-                   // Done with the zlib_adapter.
-                   delete in;
-               }
-       }
+movie_definition_sub*  create_library_movie_sub(const char* filename)
+{
+    tu_string  fn(filename);
+    printf("%s: filename is %s\n",
+          __PRETTY_FUNCTION__, filename);
+    // Is the movie already in the library?
+    {
+       smart_ptr<movie_definition_sub> m;
+       s_movie_library.get(fn, &m);
+       if (m != NULL)
+           {
+               // Return cached movie.
+               m->add_ref();
+               return m.get_ptr();
+           }
+    }
 
+    printf("%s: lineno %d\n",  __PRETTY_FUNCTION__, __LINE__);
+    // Try to open a file under the filename.
+    movie_definition_sub*      mov = create_movie_sub(filename);
 
-    /* movie_def_impl */
-    void       get_owned_fonts(array<font*>* fonts)
-       // Fill up *fonts with fonts that we own.
-       {
-           assert(fonts);
-           fonts->resize(0);
-
-           array<int>  font_ids;
-
-           for (hash<int, smart_ptr<font> >::iterator it = m_fonts.begin();
-                it != m_fonts.end();
-                ++it)
-               {
-                   font*       f = it->second.get_ptr();
-                   if (f->get_owning_movie() == this)
-                       {
-                           // Sort by character id, so the ordering is
-                           // consistent for cache read/write.
-                           int id = it->first;
-
-                           // Insert in correct place.
-                           int insert;
-                           for (insert = 0; insert < font_ids.size(); insert++)
-                               {
-                                   if (font_ids[insert] > id)
-                                       {
-                                           // We want to insert here.
-                                           break;
-                                       }
-                               }
-                           fonts->insert(insert, f);
-                           font_ids.insert(insert, id);
-                       }
-               }
+    if (mov == NULL)
+       {
+           log_error("error: couldn't load library movie '%s'\n", filename);
+           return NULL;
        }
-
-
-    /* movie_def_impl */
-    void       generate_font_bitmaps()
-       // Generate bitmaps for our fonts, if necessary.
+    else
        {
-           // Collect list of fonts.
-           array<font*>        fonts;
-           get_owned_fonts(&fonts);
-           fontlib::generate_font_bitmaps(fonts, this);
+           s_movie_library.add(fn, mov);
        }
 
+    printf("%s: lineno %d\n",  __PRETTY_FUNCTION__, __LINE__);
+    mov->add_ref();
+    return mov;
+}
+       
+movie_interface*       create_library_movie_inst(movie_definition* md)
+{
+    return create_library_movie_inst_sub((movie_definition_sub*)md);
+}
 
-    // Increment this when the cache data format changes.
-#define CACHE_FILE_VERSION 4
-
-
-    /* movie_def_impl */
-    void       output_cached_data(tu_file* out, const cache_options& options)
-       // Dump our cached data into the given stream.
-       {
-           // Write a little header.
-           char        header[5];
-           strcpy(header, "gscX");
-           header[3] = CACHE_FILE_VERSION;
-           compiler_assert(CACHE_FILE_VERSION < 256);
 
-           out->write_bytes(header, 4);
+movie_interface*       create_library_movie_inst_sub(movie_definition_sub* md)
+{
+    // Is the movie instance already in the library?
+    {
+       smart_ptr<movie_interface>      m;
+       s_movie_library_inst.get(md, &m);
+       if (m != NULL)
+           {
+               // Return cached movie instance.
+               m->add_ref();
+               return m.get_ptr();
+           }
+    }
 
-           // Write font data.
-           array<font*>        fonts;
-           get_owned_fonts(&fonts);
-           fontlib::output_cached_data(out, fonts, this, options);
+    // Try to create movie interface
+    movie_interface* mov = md->create_instance();
 
-           // Write character data.
-           {for (hash<int, smart_ptr<character_def> >::iterator it = 
m_characters.begin();
-                 it != m_characters.end();
-                 ++it)
-               {
-                   out->write_le16(it->first);
-                   it->second->output_cached_data(out, options);
-               }}
+    if (mov == NULL)
+       {
+           log_error("error: couldn't create instance\n");
 
-           out->write_le16((Sint16) -1);       // end of characters marker
+           return NULL;
        }
-
-
-    /* movie_def_impl */
-    void       input_cached_data(tu_file* in)
-       // Read in cached data and use it to prime our loaded characters.
+    else
        {
-           // Read the header & check version.
-           unsigned char       header[4];
-           in->read_bytes(header, 4);
-           if (header[0] != 'g' || header[1] != 's' || header[2] != 'c')
-               {
-                   log_error("cache file does not have the correct format; 
skipping\n");
-                   return;
-               }
-           else if (header[3] != CACHE_FILE_VERSION)
-               {
-                   log_error(
-                       "cached data is version %d, but we require version %d; 
skipping\n",
-                       int(header[3]), CACHE_FILE_VERSION);
-                   return;
-               }
-
-           // Read the cached font data.
-           array<font*>        fonts;
-           get_owned_fonts(&fonts);
-           fontlib::input_cached_data(in, fonts, this);
+           s_movie_library_inst.add(md, mov);
+       }
 
-           // Read the cached character data.
-           for (;;)
-               {
-                   if (in->get_error() != TU_FILE_NO_ERROR)
-                       {
-                           log_error("error reading cache file (characters); 
skipping\n");
-                           return;
-                       }
-                   if (in->get_eof())
-                       {
-                           log_error("unexpected eof reading cache file 
(characters); skipping\n");
-                           return;
-                       }
+    mov->add_ref();
+    return mov;
+}
 
-                   Sint16      id = in->read_le16();
-                   if (id == (Sint16) -1) { break; }   // done
-
-                   smart_ptr<character_def> ch;
-                   m_characters.get(id, &ch);
-                   if (ch != NULL)
-                       {
-                           ch->input_cached_data(in);
-                       }
-                   else
-                       {
-                           log_error("sync error in cache file (reading 
characters)!  "
-                                     "Skipping rest of cache data.\n");
-                           return;
-                       }
-               }
-       }
-
-};
 
+void   precompute_cached_data(movie_definition* movie_def)
+    // Fill in cached data in movie_def.
+    // @@@@ NEEDS TESTING -- MIGHT BE BROKEN!!!
+{
+    assert(movie_def != NULL);
 
-//
-// movie_root
-//
-// Global, shared root state for a movie and all its characters.
-//
+    // Temporarily install null render and sound handlers,
+    // so we don't get output during preprocessing.
+    //
+    // Use automatic struct var to make sure we restore
+    // when exiting the function.
+    struct save_stuff
+    {
+       render_handler* m_original_rh;
+       sound_handler*  m_original_sh;
 
-struct movie_root : public movie_interface
-{
-    smart_ptr<movie_def_impl>  m_def;
-    smart_ptr<movie>   m_movie;
-    int                        m_viewport_x0, m_viewport_y0, m_viewport_width, 
m_viewport_height;
-    float                      m_pixel_scale;
-
-    rgba                       m_background_color;
-    float                      m_timer;
-    int                        m_mouse_x, m_mouse_y, m_mouse_buttons;
-    void *                     m_userdata;
-    movie::drag_state  m_drag_state;   // @@ fold this into 
m_mouse_button_state?
-    mouse_button_state m_mouse_button_state;
-    bool                       m_on_event_load_called;
-
-    // Flags for event handlers
-    bool                       m_on_event_xmlsocket_ondata_called;
-    bool                       m_on_event_xmlsocket_onxml_called;
-    bool                       m_on_event_load_progress_called;
-    array<Timer *>     m_interval_timers;
+       save_stuff()
+           {
+               // Save.
+               m_original_rh = get_render_handler();
+               m_original_sh = get_sound_handler();
+               set_render_handler(NULL);
+               set_sound_handler(NULL);
+           }
 
-    movie_root(movie_def_impl* def)
-       :
-       m_def(def),
-       m_movie(NULL),
-       m_viewport_x0(0),
-       m_viewport_y0(0),
-       m_viewport_width(1),
-       m_viewport_height(1),
-       m_pixel_scale(1.0f),
-       m_background_color(0, 0, 0, 255),
-       m_timer(0.0f),
-       m_mouse_x(0),
-       m_mouse_y(0),
-       m_mouse_buttons(0),
-       m_userdata(NULL),
-       m_on_event_load_called(false),
-       m_on_event_xmlsocket_ondata_called(false),
-       m_on_event_xmlsocket_onxml_called(false),
-       m_on_event_load_progress_called(false)
-       {
-           assert(m_def != NULL);
-
-           set_display_viewport(0, 0, (int) m_def->get_width_pixels(), (int) 
m_def->get_height_pixels());
-       }
-
-    ~movie_root()
-       {
-           assert(m_def != NULL);
-           m_movie = NULL;
-           m_def = NULL;
-       }
-
-    // @@ should these delegate to m_movie?  Probably...
-    virtual void       set_member(const tu_stringi& name, const as_value& val) 
{}
-    virtual bool       get_member(const tu_stringi& name, as_value* val) { 
return false; }
-    virtual movie*     to_movie() { assert(0); return 0; } // @@ should this 
return m_movie.get_ptr()?
-               
+       ~save_stuff()
+           {
+               // Restore.
+               set_render_handler(m_original_rh);
+               set_sound_handler(m_original_sh);
+           }
+    } save_stuff_instance;
 
-    void       set_root_movie(movie* root_movie)
+    // Need an instance.
+    gnash::movie_interface*    m = movie_def->create_instance();
+    if (m == NULL)
        {
-           m_movie = root_movie;
-           assert(m_movie != NULL);
+           log_error("error: precompute_cached_data can't create instance of 
movie\n");
+           return;
        }
-
-    void       set_display_viewport(int x0, int y0, int w, int h)
+               
+    // Run through the movie's frames.
+    //
+    // @@ there might be cleaner ways to do this; e.g. do
+    // execute_frame_tags(i, true) on movie and all child
+    // sprites.
+    int        kick_count = 0;
+    for (;;)
        {
-           m_viewport_x0 = x0;
-           m_viewport_y0 = y0;
-           m_viewport_width = w;
-           m_viewport_height = h;
+           // @@ do we also have to run through all sprite frames
+           // as well?
+           //
+           // @@ also, ActionScript can rescale things
+           // dynamically -- we can't really do much about that I
+           // guess?
+           //
+           // @@ Maybe we should allow the user to specify some
+           // safety margin on scaled shapes.
 
-           // Recompute pixel scale.
-           float       scale_x = m_viewport_width / 
TWIPS_TO_PIXELS(m_def->m_frame_size.width());
-           float       scale_y = m_viewport_height / 
TWIPS_TO_PIXELS(m_def->m_frame_size.height());
-           m_pixel_scale = fmax(scale_x, scale_y);
-       }
+           int last_frame = m->get_current_frame();
+           m->advance(0.010f);
+           m->display();
 
+           if (m->get_current_frame() == movie_def->get_frame_count() - 1)
+               {
+                   // Done.
+                   break;
+               }
 
-    void       notify_mouse_state(int x, int y, int buttons)
-       // The host app uses this to tell the movie where the
-       // user's mouse pointer is.
-       {
-           m_mouse_x = x;
-           m_mouse_y = y;
-           m_mouse_buttons = buttons;
+           if (m->get_play_state() == gnash::movie_interface::STOP)
+               {
+                   // Kick the movie.
+                   //printf("kicking movie, kick ct = %d\n", kick_count);
+                   m->goto_frame(last_frame + 1);
+                   m->set_play_state(gnash::movie_interface::PLAY);
+                   kick_count++;
+
+                   if (kick_count > 10)
+                       {
+                           //printf("movie is stalled; giving up on playing it 
through.\n");
+                           break;
+                       }
+               }
+           else if (m->get_current_frame() < last_frame)
+               {
+                   // Hm, apparently we looped back.  Skip ahead...
+                   log_error("loop back; jumping to frame %d\n", last_frame);
+                   m->goto_frame(last_frame + 1);
+               }
+           else
+               {
+                   kick_count = 0;
+               }
        }
 
-    virtual void       get_mouse_state(int* x, int* y, int* buttons)
-       // Use this to retrieve the last state of the mouse, as set via
-       // notify_mouse_state().  Coordinates are in PIXELS, NOT TWIPS.
-       {
-           assert(x);
-           assert(y);
-           assert(buttons);
+    m->drop_ref();
+}
 
-           *x = m_mouse_x;
-           *y = m_mouse_y;
-           *buttons = m_mouse_buttons;
-       }
 
-    movie*     get_root_movie() { return m_movie.get_ptr(); }
+//
+// Some tag implementations
+//
 
 
-    void       stop_drag()
-       {
-           m_drag_state.m_character = NULL;
-       }
+void   null_loader(stream* in, int tag_type, movie_definition_sub* m)
+    // Silently ignore the contents of this tag.
+{
+}
 
+void   frame_label_loader(stream* in, int tag_type, movie_definition_sub* m)
+    // Label the current frame of m with the name from the stream.
+{
+    char*      n = in->read_string();
+    m->add_frame_name(n);
+    delete [] n;
+}
 
-    movie_definition*  get_movie_definition() { return 
m_movie->get_movie_definition(); }
+struct set_background_color : public execute_tag
+{
+    rgba       m_color;
 
-    uint32     get_file_bytes() const
+    void       execute(movie* m)
        {
-           return m_def->get_file_bytes();
+           float       current_alpha = m->get_background_alpha();
+           m_color.m_a = frnd(current_alpha * 255.0f);
+           m->set_background_color(m_color);
        }
 
-    virtual int    add_interval_timer(void *timer)
-       {
-           Timer *ptr = static_cast<Timer *>(timer);
-                       
-           m_interval_timers.push_back(ptr);
-           return m_interval_timers.size();
-       }
-       
-    virtual void    clear_interval_timer(int x)
-       {
-           m_interval_timers.remove(x-1);
-           //m_interval_timers[x]->clearInterval();
-       }
-       
-    virtual void    do_something(void *timer)
+    void       execute_state(movie* m)
        {
-           log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
+           execute(m);
        }
-               
-    // 0-based!!
-    int        get_current_frame() const { return 
m_movie->get_current_frame(); }
-    float      get_frame_rate() const { return m_def->get_frame_rate(); }
 
-    virtual float      get_pixel_scale() const
-       // Return the size of a logical movie pixel as
-       // displayed on-screen, with the current device
-       // coordinates.
+    void       read(stream* in)
        {
-           return m_pixel_scale;
-       }
+           m_color.read_rgb(in);
 
-    // @@ Is this one necessary?
-    character* get_character(int character_id)
-       {
-           return m_movie->get_character(character_id);
+           IF_VERBOSE_PARSE(log_msg("  set_background_color: (%d %d %d)\n",
+                                    m_color.m_r, m_color.m_g, m_color.m_b));
        }
+};
 
-    void       set_background_color(const rgba& color)
-       {
-           m_background_color = color;
-       }
 
-    void       set_background_alpha(float alpha)
-       {
-           m_background_color.m_a = iclamp(frnd(alpha * 255.0f), 0, 255);
-       }
+void   set_background_color_loader(stream* in, int tag_type, 
movie_definition_sub* m)
+{
+    assert(tag_type == 9);
+    assert(m);
 
-    float      get_background_alpha() const
-       {
-           return m_background_color.m_a / 255.0f;
-       }
+    set_background_color*      t = new set_background_color;
+    t->read(in);
 
-    float      get_timer() const { return m_timer; }
+    m->add_execute_tag(t);
+}
 
-    void       restart() { m_movie->restart(); }
-               
-    void       advance(float delta_time)
-       {
-//         printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
-           int i;
-           if (m_on_event_load_called == false)
-               {
-                   // Must do loading events.  For child sprites this is
-                   // done by the dlist, but root movies don't get added
-                   // to a dlist, so we do it here.
-                   m_on_event_load_called = true;
-                   m_movie->on_event_load();
-               }
 #if 0
-           // Must check the socket connection for data
-           if (m_on_event_xmlsocket_ondata_called == true) {
-               m_movie->on_event_xmlsocket_ondata();
-           }
-                       
-           if (m_on_event_xmlsocket_onxml_called == true) {
-               m_movie->on_event_xmlsocket_onxml();
-           }
+// Bitmap character
+struct bitmap_character : public bitmap_character_def
+{
+    bitmap_character(bitmap_info* bi)
+       :
+       m_bitmap_info(bi)
+       {
+       }
+
+//             bitmap_character(image::rgb* image)
+//             {
+//                     assert(image != 0);
 
+//                     // Create our bitmap info, from our image.
+//                     m_bitmap_info = 
gnash::render::create_bitmap_info_rgb(image);
+//             }
 
-           // Must check the progress of the MovieClip being loaded
-           if (m_on_event_load_progress_called == true) {
-               m_movie->on_event_load_progress();                              
-           }
-#endif
-           if (m_interval_timers.size() > 0) {
-               for (i=0; i<m_interval_timers.size(); i++) {
-                   if (m_interval_timers[i]->expired()) {
-                       // printf("FIXME: Interval Timer Expired!\n");
-                       //m_movie->on_event_interval_timer();
-                       m_movie->do_something(m_interval_timers[i]);
-                       // 
clear_interval_timer(m_interval_timers[i]->getIntervalID()); // FIXME: we 
shouldn't really disable the timer here
-                   }
-               }
-           }
-                       
-                       
-           m_timer += delta_time;
-           // @@ TODO handle multi-frame catch-up stuff
-           // here, and make it optional.  Make
-           // movie::advance() a fixed framerate w/ no
-           // dt.
+//             bitmap_character(image::rgba* image)
+//             {
+//                     assert(image != 0);
 
-           // Handle the mouse.
-           m_mouse_button_state.m_topmost_entity =
-               m_movie->get_topmost_mouse_entity(PIXELS_TO_TWIPS(m_mouse_x), 
PIXELS_TO_TWIPS(m_mouse_y));
-           m_mouse_button_state.m_mouse_button_state_current = 
(m_mouse_buttons & 1);
-           generate_mouse_button_events(&m_mouse_button_state);
+//                     // Create our bitmap info, from our image.
+//                     m_bitmap_info = 
gnash::render::create_bitmap_info_rgba(image);
+//             }
 
-           m_movie->advance(delta_time);
+    gnash::bitmap_info*        get_bitmap_info()
+       {
+           return m_bitmap_info.get_ptr();
        }
 
-    // 0-based!!
-    void       goto_frame(int target_frame_number) { 
m_movie->goto_frame(target_frame_number); }
+private:
+    smart_ptr<gnash::bitmap_info>      m_bitmap_info;
+};
+#endif
 
-    virtual bool       has_looped() const { return m_movie->has_looped(); }
+void   jpeg_tables_loader(stream* in, int tag_type, movie_definition_sub* m)
+    // Load JPEG compression tables that can be used to load
+    // images further along in the stream.
+{
+    assert(tag_type == 8);
 
-    void       display()
-       {
-           if (m_movie->get_visible() == false)
-               {
-                   // Don't display.
-                   return;
-               }
+#if TU_CONFIG_LINK_TO_JPEGLIB
+    jpeg::input*       j_in = 
jpeg::input::create_swf_jpeg2_header_only(in->get_underlying_stream());
+    assert(j_in);
 
-           gnash::render::begin_display(
-               m_background_color,
-               m_viewport_x0, m_viewport_y0,
-               m_viewport_width, m_viewport_height,
-               m_def->m_frame_size.m_x_min, m_def->m_frame_size.m_x_max,
-               m_def->m_frame_size.m_y_min, m_def->m_frame_size.m_y_max);
+    m->set_jpeg_loader(j_in);
+#endif // TU_CONFIG_LINK_TO_JPEGLIB
+}
 
-           m_movie->display();
 
-           gnash::render::end_display();
-       }
+void   define_bits_jpeg_loader(stream* in, int tag_type, movie_definition_sub* 
m)
+    // A JPEG image without included tables; those should be in an
+    // existing jpeg::input object stored in the movie.
+{
+    assert(tag_type == 6);
 
-    virtual bool       goto_labeled_frame(const char* label)
-       {
-           int target_frame = -1;
-           if (m_def->get_labeled_frame(label, &target_frame))
-               {
-                   goto_frame(target_frame);
-                   return true;
-               }
-           else
-               {
-                   IF_VERBOSE_ACTION(
-                       log_error("error: movie_impl::goto_labeled_frame('%s') 
unknown label\n", label));
-                   return false;
-               }
-       }
+    Uint16     character_id = in->read_u16();
 
-    virtual void       set_play_state(play_state s) { 
m_movie->set_play_state(s); }
-    virtual play_state get_play_state() const { return 
m_movie->get_play_state(); }
+    //
+    // Read the image data.
+    //
+    bitmap_info*       bi = NULL;
 
-    /* movie_root */
-    virtual void       set_variable(const char* path_to_var, const char* 
new_value)
+    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
        {
-           m_movie->set_variable(path_to_var, new_value);
-       }
+#if TU_CONFIG_LINK_TO_JPEGLIB
+           jpeg::input*        j_in = m->get_jpeg_loader();
+           assert(j_in);
+           j_in->discard_partial_buffer();
 
-    /* movie_root */
-    virtual void       set_variable(const char* path_to_var, const wchar_t* 
new_value)
-       {
-           m_movie->set_variable(path_to_var, new_value);
+           image::rgb* im = image::read_swf_jpeg2_with_tables(j_in);
+           bi = render::create_bitmap_info_rgb(im);
+           delete im;
+#else
+           log_error("gnash is not linked to jpeglib -- can't load jpeg image 
data!\n");
+           bi = render::create_bitmap_info_empty();
+#endif
        }
-
-    virtual const char*        get_variable(const char* path_to_var) const
+    else
        {
-           return m_movie->get_variable(path_to_var);
+           bi = render::create_bitmap_info_empty();
        }
 
-    /*movie_root*/
-    // For ActionScript interfacing convenience.
-    virtual const char*        call_method(const char* method_name, const 
char* method_arg_fmt, ...)
-       {
-           assert(m_movie != NULL);
+    assert(bi->get_ref_count() == 0);
 
-           va_list     args;
-           va_start(args, method_arg_fmt);
-           const char* result = m_movie->call_method_args(method_name, 
method_arg_fmt, args);
-           va_end(args);
+    bitmap_character*  ch = new bitmap_character(bi);
 
-           return result;
-       }
-
-    /*movie_root*/
-    virtual const char*        call_method_args(const char* method_name, const 
char* method_arg_fmt, va_list args)
-       {
-           assert(m_movie != NULL);
-           return m_movie->call_method_args(method_name, method_arg_fmt, args);
-       }
-
-    virtual void       set_visible(bool visible) { 
m_movie->set_visible(visible); }
-    virtual bool       get_visible() const { return m_movie->get_visible(); }
-
-    virtual void * get_userdata() { return m_userdata; }
-    virtual void set_userdata(void * ud ) { m_userdata = ud;  }
-
-    virtual void       attach_display_callback(const char* path_to_object, 
void (*callback)(void* user_ptr), void* user_ptr)
-       {
-           m_movie->attach_display_callback(path_to_object, callback, 
user_ptr);
-       }
-};
-
-
-static void    ensure_loaders_registered()
-{
-    static bool        s_registered = false;
-       
-    if (s_registered == false)
-       {
-           // Register the standard loaders.
-           s_registered = true;
-           register_tag_loader(0, end_loader);
-           register_tag_loader(2, define_shape_loader);
-           register_tag_loader(4, place_object_2_loader);
-           register_tag_loader(5, remove_object_2_loader);
-           register_tag_loader(6, define_bits_jpeg_loader);
-           register_tag_loader(7, button_character_loader);
-           register_tag_loader(8, jpeg_tables_loader);
-           register_tag_loader(9, set_background_color_loader);
-           register_tag_loader(10, define_font_loader);
-           register_tag_loader(11, define_text_loader);
-           register_tag_loader(12, do_action_loader);
-           register_tag_loader(13, define_font_info_loader);
-           register_tag_loader(14, define_sound_loader);
-           register_tag_loader(15, start_sound_loader);
-           register_tag_loader(17, button_sound_loader);
-           register_tag_loader(20, define_bits_lossless_2_loader);
-           register_tag_loader(21, define_bits_jpeg2_loader);
-           register_tag_loader(22, define_shape_loader);
-           register_tag_loader(24, null_loader);       // "protect" tag; we're 
not an authoring tool so we don't care.
-           register_tag_loader(26, place_object_2_loader);
-           register_tag_loader(28, remove_object_2_loader);
-           register_tag_loader(32, define_shape_loader);
-           register_tag_loader(33, define_text_loader);
-           register_tag_loader(37, define_edit_text_loader);
-           register_tag_loader(34, button_character_loader);
-           register_tag_loader(35, define_bits_jpeg3_loader);
-           register_tag_loader(36, define_bits_lossless_2_loader);
-           register_tag_loader(39, sprite_loader);
-           register_tag_loader(43, frame_label_loader);
-           register_tag_loader(46, define_shape_morph_loader);
-           register_tag_loader(48, define_font_loader);
-           register_tag_loader(56, export_loader);
-           register_tag_loader(57, import_loader);
-           register_tag_loader(59, do_init_action_loader);   
-       }
-}
-
-
-
-void   get_movie_info(
-    const char* filename,
-    int* version,
-    int* width,
-    int* height,
-    float* frames_per_second,
-    int* frame_count,
-    int* tag_count
-    )
-    // Attempt to read the header of the given .swf movie file.
-    // Put extracted info in the given vars.
-    // Sets *version to 0 if info can't be extracted.
-{
-    if (s_opener_function == NULL)
-       {
-           log_error("error: get_movie_info(): no file opener function 
registered\n");
-           if (version) *version = 0;
-           return;
-       }
-
-    tu_file*   in = s_opener_function(filename);
-    if (in == NULL || in->get_error() != TU_FILE_NO_ERROR)
-       {
-           log_error("error: get_movie_info(): can't open '%s'\n", filename);
-           if (version) *version = 0;
-           delete in;
-           return;
-       }
-
-    Uint32     file_start_pos = in->get_position();
-    Uint32     header = in->read_le32();
-    Uint32     file_length = in->read_le32();
-    Uint32     file_end_pos = file_start_pos + file_length;
-
-    int        local_version = (header >> 24) & 255;
-    if ((header & 0x0FFFFFF) != 0x00535746
-       && (header & 0x0FFFFFF) != 0x00535743)
-       {
-           // ERROR
-           log_error("error: get_movie_info(): file '%s' does not start with a 
SWF header!\n", filename);
-           if (version) *version = 0;
-           delete in;
-           return;
-       }
-    bool       compressed = (header & 255) == 'C';
-
-    tu_file*   original_in = NULL;
-    if (compressed)
-       {
-#if TU_CONFIG_LINK_TO_ZLIB == 0
-           log_error("get_movie_info(): can't read zipped SWF data; 
TU_CONFIG_LINK_TO_ZLIB is 0!\n");
-           return;
-#endif
-           original_in = in;
-
-           // Uncompress the input as we read it.
-           in = zlib_adapter::make_inflater(original_in);
-
-           // Subtract the size of the 8-byte header, since
-           // it's not included in the compressed
-           // stream length.
-           file_length -= 8;
-       }
-
-    stream     str(in);
-
-    rect       frame_size;
-    frame_size.read(&str);
-
-    float      local_frame_rate = str.read_u16() / 256.0f;
-    int        local_frame_count = str.read_u16();
-
-    if (version) *version = local_version;
-    if (width) *width = int(frame_size.width() / 20.0f + 0.5f);
-    if (height) *height = int(frame_size.height() / 20.0f + 0.5f);
-    if (frames_per_second) *frames_per_second = local_frame_rate;
-    if (frame_count) *frame_count = local_frame_count;
-
-    if (tag_count)
-       {
-           // Count tags.
-           int local_tag_count = 0;
-           while ((Uint32) str.get_position() < file_end_pos)
-               {
-                   str.open_tag();
-                   str.close_tag();
-                   local_tag_count++;
-               }
-           *tag_count = local_tag_count;
-       }
-
-    delete in;
-    delete original_in;
-}
-
-
-
-movie_definition*      create_movie(const char* filename)
-    // Create the movie definition from the specified .swf file.
-{
-    return create_movie_sub(filename);
-}
-
-
-movie_definition_sub*  create_movie_sub(const char* filename)
-{
-    printf("%s: filename is %s\n",  __PRETTY_FUNCTION__, filename);
-    if (s_opener_function == NULL)
-       {
-           // Don't even have a way to open the file.
-           log_error("error: no file opener function; can't create movie.  "
-                     "See gnash::register_file_opener_callback\n");
-           return NULL;
-       }
-
-    tu_file* in = s_opener_function(filename);
-    if (in == NULL)
-       {
-           log_error("failed to open '%s'; can't create movie.\n", filename);
-           return NULL;
-       }
-    else if (in->get_error())
-       {
-           log_error("error: file opener can't open '%s'\n", filename);
-           return NULL;
-       }
-
-    ensure_loaders_registered();
-
-    movie_def_impl*    m = new movie_def_impl(DO_LOAD_BITMAPS, 
DO_LOAD_FONT_SHAPES);
-    m->read(in);
-
-    delete in;
-
-    if (m && s_use_cache_files)
-       {
-           // Try to load a .gsc file.
-           tu_string   cache_filename(filename);
-           cache_filename += ".gsc";
-           tu_file*    cache_in = s_opener_function(cache_filename.c_str());
-           if (cache_in == NULL
-               || cache_in->get_error() != TU_FILE_NO_ERROR)
-               {
-                   // Can't open cache file; don't sweat it.
-                   IF_VERBOSE_PARSE(log_msg("note: couldn't open cache file 
'%s'\n", cache_filename.c_str()));
-
-                   m->generate_font_bitmaps(); // can't read cache, so 
generate font texture data.
-               }
-           else
-               {
-                   // Load the cached data.
-                   m->input_cached_data(cache_in);
-               }
-
-           delete cache_in;
-       }
-
-    m->add_ref();
-    return m;
-}
-
-
-static bool    s_no_recurse_while_loading = false;     // @@ TODO get rid of 
this; make it the normal mode.
-
-
-movie_definition*      create_movie_no_recurse(
-    tu_file* in,
-    create_bitmaps_flag cbf,
-    create_font_shapes_flag cfs)
-{
-    ensure_loaders_registered();
-
-    // @@ TODO make no_recurse the standard way to load.
-    // In create_movie(), use the visit_ API to keep
-    // visiting dependent movies, until everything is
-    // loaded.  That way we only have one code path and
-    // the resource_proxy stuff gets tested.
-    s_no_recurse_while_loading = true;
-
-    movie_def_impl*    m = new movie_def_impl(cbf, cfs);
-    m->read(in);
-
-    s_no_recurse_while_loading = false;
-
-    m->add_ref();
-    return m;
-}
-
-
-//
-// global gnash management
-//
-
-
-// For built-in sprite ActionScript methods.
-as_object*     s_sprite_builtins = 0;  // shared among all sprites.
-static void    sprite_builtins_init();
-static void    sprite_builtins_clear();
-
-
-void   clear()
-    // Maximum release of resources.
-{
-    clear_library();
-    sprite_builtins_clear();
-    fontlib::clear();
-    action_clear();
-}
-
-
-//
-// library stuff, for sharing resources among different movies.
-//
-
-
-static stringi_hash< smart_ptr<movie_definition_sub> > s_movie_library;
-static hash< movie_definition_sub*, smart_ptr<movie_interface> >       
s_movie_library_inst;
-static array<movie_interface*> s_extern_sprites;
-static movie_interface* s_current_root;
-
-static tu_string s_workdir;
-
-void save_extern_movie(movie_interface* m)
-{
-    s_extern_sprites.push_back(m);
-}
-
-//#if 0
-void delete_unused_root()
-{
-    for (int i = 0; i < s_extern_sprites.size(); i++)
-       {
-           movie_interface* root_m = s_extern_sprites[i];
-           movie* m = root_m->get_root_movie();
-      
-           if (m->get_ref_count() < 2)
-               {
-                   IF_VERBOSE_ACTION(log_msg("extern movie deleted\n"));
-                   s_extern_sprites.remove(i);
-                   i--;
-                   root_m->drop_ref();
-               }
-       }
-}
-//#endif // 0
-
-movie_interface* get_current_root()
-{
-    assert(s_current_root != NULL);
-    return s_current_root;
-}
-
-void set_current_root(movie_interface* m)
-{
-    assert(m != NULL);
-    s_current_root = m;
-}
-
-const char* get_workdir()
-{
-    return s_workdir.c_str();
-}
-
-void set_workdir(const char* dir)
-{
-    assert(dir != NULL);
-    s_workdir = dir;
-}
-
-void   clear_library()
-    // Drop all library references to movie_definitions, so they
-    // can be cleaned up.
-{
-    s_movie_library.clear();
-    s_movie_library_inst.clear();
-}
-
-movie_definition*      create_library_movie(const char* filename)
-    // Try to load a movie from the given url, if we haven't
-    // loaded it already.  Add it to our library on success, and
-    // return a pointer to it.
-{
-    return create_library_movie_sub(filename);
-}
-
-
-movie_definition_sub*  create_library_movie_sub(const char* filename)
-{
-    tu_string  fn(filename);
-    printf("%s: filename is %s\n",
-          __PRETTY_FUNCTION__, filename);
-    // Is the movie already in the library?
-    {
-       smart_ptr<movie_definition_sub> m;
-       s_movie_library.get(fn, &m);
-       if (m != NULL)
-           {
-               // Return cached movie.
-               m->add_ref();
-               return m.get_ptr();
-           }
-    }
-
-    printf("%s: lineno %d\n",  __PRETTY_FUNCTION__, __LINE__);
-    // Try to open a file under the filename.
-    movie_definition_sub*      mov = create_movie_sub(filename);
-
-    if (mov == NULL)
-       {
-           log_error("error: couldn't load library movie '%s'\n", filename);
-           return NULL;
-       }
-    else
-       {
-           s_movie_library.add(fn, mov);
-       }
-
-    printf("%s: lineno %d\n",  __PRETTY_FUNCTION__, __LINE__);
-    mov->add_ref();
-    return mov;
-}
-       
-movie_interface*       create_library_movie_inst(movie_definition* md)
-{
-    return create_library_movie_inst_sub((movie_definition_sub*)md);
-}
-
-
-movie_interface*       create_library_movie_inst_sub(movie_definition_sub* md)
-{
-    // Is the movie instance already in the library?
-    {
-       smart_ptr<movie_interface>      m;
-       s_movie_library_inst.get(md, &m);
-       if (m != NULL)
-           {
-               // Return cached movie instance.
-               m->add_ref();
-               return m.get_ptr();
-           }
-    }
-
-    // Try to create movie interface
-    movie_interface* mov = md->create_instance();
-
-    if (mov == NULL)
-       {
-           log_error("error: couldn't create instance\n");
-
-           return NULL;
-       }
-    else
-       {
-           s_movie_library_inst.add(md, mov);
-       }
-
-    mov->add_ref();
-    return mov;
-}
-
-
-void   precompute_cached_data(movie_definition* movie_def)
-    // Fill in cached data in movie_def.
-    // @@@@ NEEDS TESTING -- MIGHT BE BROKEN!!!
-{
-    assert(movie_def != NULL);
-
-    // Temporarily install null render and sound handlers,
-    // so we don't get output during preprocessing.
-    //
-    // Use automatic struct var to make sure we restore
-    // when exiting the function.
-    struct save_stuff
-    {
-       render_handler* m_original_rh;
-       sound_handler*  m_original_sh;
-
-       save_stuff()
-           {
-               // Save.
-               m_original_rh = get_render_handler();
-               m_original_sh = get_sound_handler();
-               set_render_handler(NULL);
-               set_sound_handler(NULL);
-           }
-
-       ~save_stuff()
-           {
-               // Restore.
-               set_render_handler(m_original_rh);
-               set_sound_handler(m_original_sh);
-           }
-    } save_stuff_instance;
-
-    // Need an instance.
-    gnash::movie_interface*    m = movie_def->create_instance();
-    if (m == NULL)
-       {
-           log_error("error: precompute_cached_data can't create instance of 
movie\n");
-           return;
-       }
-               
-    // Run through the movie's frames.
-    //
-    // @@ there might be cleaner ways to do this; e.g. do
-    // execute_frame_tags(i, true) on movie and all child
-    // sprites.
-    int        kick_count = 0;
-    for (;;)
-       {
-           // @@ do we also have to run through all sprite frames
-           // as well?
-           //
-           // @@ also, ActionScript can rescale things
-           // dynamically -- we can't really do much about that I
-           // guess?
-           //
-           // @@ Maybe we should allow the user to specify some
-           // safety margin on scaled shapes.
-
-           int last_frame = m->get_current_frame();
-           m->advance(0.010f);
-           m->display();
-
-           if (m->get_current_frame() == movie_def->get_frame_count() - 1)
-               {
-                   // Done.
-                   break;
-               }
-
-           if (m->get_play_state() == gnash::movie_interface::STOP)
-               {
-                   // Kick the movie.
-                   //printf("kicking movie, kick ct = %d\n", kick_count);
-                   m->goto_frame(last_frame + 1);
-                   m->set_play_state(gnash::movie_interface::PLAY);
-                   kick_count++;
-
-                   if (kick_count > 10)
-                       {
-                           //printf("movie is stalled; giving up on playing it 
through.\n");
-                           break;
-                       }
-               }
-           else if (m->get_current_frame() < last_frame)
-               {
-                   // Hm, apparently we looped back.  Skip ahead...
-                   log_error("loop back; jumping to frame %d\n", last_frame);
-                   m->goto_frame(last_frame + 1);
-               }
-           else
-               {
-                   kick_count = 0;
-               }
-       }
-
-    m->drop_ref();
-}
-
-
-//
-// Some tag implementations
-//
-
-
-void   null_loader(stream* in, int tag_type, movie_definition_sub* m)
-    // Silently ignore the contents of this tag.
-{
-}
-
-void   frame_label_loader(stream* in, int tag_type, movie_definition_sub* m)
-    // Label the current frame of m with the name from the stream.
-{
-    char*      n = in->read_string();
-    m->add_frame_name(n);
-    delete [] n;
-}
-
-struct set_background_color : public execute_tag
-{
-    rgba       m_color;
-
-    void       execute(movie* m)
-       {
-           float       current_alpha = m->get_background_alpha();
-           m_color.m_a = frnd(current_alpha * 255.0f);
-           m->set_background_color(m_color);
-       }
-
-    void       execute_state(movie* m)
-       {
-           execute(m);
-       }
-
-    void       read(stream* in)
-       {
-           m_color.read_rgb(in);
-
-           IF_VERBOSE_PARSE(log_msg("  set_background_color: (%d %d %d)\n",
-                                    m_color.m_r, m_color.m_g, m_color.m_b));
-       }
-};
-
-
-void   set_background_color_loader(stream* in, int tag_type, 
movie_definition_sub* m)
-{
-    assert(tag_type == 9);
-    assert(m);
-
-    set_background_color*      t = new set_background_color;
-    t->read(in);
-
-    m->add_execute_tag(t);
-}
-
-#if 0
-// Bitmap character
-struct bitmap_character : public bitmap_character_def
-{
-    bitmap_character(bitmap_info* bi)
-       :
-       m_bitmap_info(bi)
-       {
-       }
-
-//             bitmap_character(image::rgb* image)
-//             {
-//                     assert(image != 0);
-
-//                     // Create our bitmap info, from our image.
-//                     m_bitmap_info = 
gnash::render::create_bitmap_info_rgb(image);
-//             }
-
-//             bitmap_character(image::rgba* image)
-//             {
-//                     assert(image != 0);
-
-//                     // Create our bitmap info, from our image.
-//                     m_bitmap_info = 
gnash::render::create_bitmap_info_rgba(image);
-//             }
-
-    gnash::bitmap_info*        get_bitmap_info()
-       {
-           return m_bitmap_info.get_ptr();
-       }
-
-private:
-    smart_ptr<gnash::bitmap_info>      m_bitmap_info;
-};
-#endif
-
-void   jpeg_tables_loader(stream* in, int tag_type, movie_definition_sub* m)
-    // Load JPEG compression tables that can be used to load
-    // images further along in the stream.
-{
-    assert(tag_type == 8);
-
-#if TU_CONFIG_LINK_TO_JPEGLIB
-    jpeg::input*       j_in = 
jpeg::input::create_swf_jpeg2_header_only(in->get_underlying_stream());
-    assert(j_in);
-
-    m->set_jpeg_loader(j_in);
-#endif // TU_CONFIG_LINK_TO_JPEGLIB
-}
-
-
-void   define_bits_jpeg_loader(stream* in, int tag_type, movie_definition_sub* 
m)
-    // A JPEG image without included tables; those should be in an
-    // existing jpeg::input object stored in the movie.
-{
-    assert(tag_type == 6);
-
-    Uint16     character_id = in->read_u16();
-
-    //
-    // Read the image data.
-    //
-    bitmap_info*       bi = NULL;
-
-    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
-       {
-#if TU_CONFIG_LINK_TO_JPEGLIB
-           jpeg::input*        j_in = m->get_jpeg_loader();
-           assert(j_in);
-           j_in->discard_partial_buffer();
-
-           image::rgb* im = image::read_swf_jpeg2_with_tables(j_in);
-           bi = render::create_bitmap_info_rgb(im);
-           delete im;
-#else
-           log_error("gnash is not linked to jpeglib -- can't load jpeg image 
data!\n");
-           bi = render::create_bitmap_info_empty();
-#endif
-       }
-    else
-       {
-           bi = render::create_bitmap_info_empty();
-       }
-
-    assert(bi->get_ref_count() == 0);
-
-    bitmap_character*  ch = new bitmap_character(bi);
-
-    m->add_bitmap_character(character_id, ch);
-}
-
-
-void   define_bits_jpeg2_loader(stream* in, int tag_type, 
movie_definition_sub* m)
-{
-    assert(tag_type == 21);
-               
-    Uint16     character_id = in->read_u16();
-
-    IF_VERBOSE_PARSE(log_msg("  define_bits_jpeg2_loader: charid = %d pos = 
0x%x\n", character_id, in->get_position()));
-
-    //
-    // Read the image data.
-    //
-               
-    bitmap_info*       bi = NULL;
-
-    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
-       {
-#if TU_CONFIG_LINK_TO_JPEGLIB
-           image::rgb* im = image::read_swf_jpeg2(in->get_underlying_stream());
-           bi = render::create_bitmap_info_rgb(im);
-           delete im;
-#else
-           log_error("gnash is not linked to jpeglib -- can't load jpeg image 
data!\n");
-           bi = render::create_bitmap_info_empty();
-#endif
-       }
-    else
-       {
-           bi = render::create_bitmap_info_empty();
-       }
-
-    assert(bi->get_ref_count() == 0);
-
-    bitmap_character*  ch = new bitmap_character(bi);
-
-    m->add_bitmap_character(character_id, ch);
-}
-
-
-#if TU_CONFIG_LINK_TO_ZLIB
-void   inflate_wrapper(tu_file* in, void* buffer, int buffer_bytes)
-    // Wrapper function -- uses Zlib to uncompress in_bytes worth
-    // of data from the input file into buffer_bytes worth of data
-    // into *buffer.
-{
-    assert(in);
-    assert(buffer);
-    assert(buffer_bytes > 0);
-
-    int err;
-    z_stream d_stream; /* decompression stream */
-
-    d_stream.zalloc = (alloc_func)0;
-    d_stream.zfree = (free_func)0;
-    d_stream.opaque = (voidpf)0;
-
-    d_stream.next_in  = 0;
-    d_stream.avail_in = 0;
-
-    d_stream.next_out = (Byte*) buffer;
-    d_stream.avail_out = (uInt) buffer_bytes;
-
-    err = inflateInit(&d_stream);
-    if (err != Z_OK) {
-       log_error("error: inflate_wrapper() inflateInit() returned %d\n", err);
-       return;
-    }
-
-    Uint8      buf[1];
-
-    for (;;) {
-       // Fill a one-byte (!) buffer.
-       buf[0] = in->read_byte();
-       d_stream.next_in = &buf[0];
-       d_stream.avail_in = 1;
-
-       err = inflate(&d_stream, Z_SYNC_FLUSH);
-       if (err == Z_STREAM_END) break;
-       if (err != Z_OK)
-           {
-               log_error("error: inflate_wrapper() inflate() returned %d\n", 
err);
-           }
-    }
-
-    err = inflateEnd(&d_stream);
-    if (err != Z_OK)
-       {
-           log_error("error: inflate_wrapper() inflateEnd() return %d\n", err);
-       }
-}
-#endif // TU_CONFIG_LINK_TO_ZLIB
-
-
-void   define_bits_jpeg3_loader(stream* in, int tag_type, 
movie_definition_sub* m)
-    // loads a define_bits_jpeg3 tag. This is a jpeg file with an alpha
-    // channel using zlib compression.
-{
-    assert(tag_type == 35);
-
-    Uint16     character_id = in->read_u16();
-
-    IF_VERBOSE_PARSE(log_msg("  define_bits_jpeg3_loader: charid = %d pos = 
0x%x\n", character_id, in->get_position()));
-
-    Uint32     jpeg_size = in->read_u32();
-    Uint32     alpha_position = in->get_position() + jpeg_size;
-
-    bitmap_info*       bi = NULL;
-
-    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
-       {
-#if TU_CONFIG_LINK_TO_JPEGLIB == 0 || TU_CONFIG_LINK_TO_ZLIB == 0
-           log_error("gnash is not linked to jpeglib/zlib -- can't load 
jpeg/zipped image data!\n");
-           bi = render::create_bitmap_info_empty();
-#else
-           //
-           // Read the image data.
-           //
-               
-           // Read rgb data.
-           image::rgba*        im = 
image::read_swf_jpeg3(in->get_underlying_stream());
-
-           // Read alpha channel.
-           in->set_position(alpha_position);
-
-           int buffer_bytes = im->m_width * im->m_height;
-           Uint8*      buffer = new Uint8[buffer_bytes];
-
-           inflate_wrapper(in->get_underlying_stream(), buffer, buffer_bytes);
-
-           for (int i = 0; i < buffer_bytes; i++)
-               {
-                   im->m_data[4*i+3] = buffer[i];
-               }
-
-           delete [] buffer;
-
-           bi = render::create_bitmap_info_rgba(im);
-
-           delete im;
-#endif
-
-       }
-    else
-       {
-           bi = render::create_bitmap_info_empty();
-       }
-
-    // Create bitmap character.
-    bitmap_character*  ch = new bitmap_character(bi);
-
-    m->add_bitmap_character(character_id, ch);
-}
-
-
-void   define_bits_lossless_2_loader(stream* in, int tag_type, 
movie_definition_sub* m)
-{
-    assert(tag_type == 20 || tag_type == 36);
-
-    Uint16     character_id = in->read_u16();
-    Uint8      bitmap_format = in->read_u8();  // 3 == 8 bit, 4 == 16 bit, 5 
== 32 bit
-    Uint16     width = in->read_u16();
-    Uint16     height = in->read_u16();
-
-    IF_VERBOSE_PARSE(log_msg("  defbitslossless2: tag_type = %d, id = %d, fmt 
= %d, w = %d, h = %d\n",
-                            tag_type,
-                            character_id,
-                            bitmap_format,
-                            width,
-                            height));
-
-    bitmap_info*       bi = NULL;
-    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
-       {
-#if TU_CONFIG_LINK_TO_ZLIB == 0
-           log_error("gnash is not linked to zlib -- can't load zipped image 
data!\n");
-           return;
-#else
-           if (tag_type == 20)
-               {
-                   // RGB image data.
-                   image::rgb* image = image::create_rgb(width, height);
-
-                   if (bitmap_format == 3)
-                       {
-                           // 8-bit data, preceded by a palette.
-
-                           const int   bytes_per_pixel = 1;
-                           int color_table_size = in->read_u8();
-                           color_table_size += 1;      // !! SWF stores one 
less than the actual size
-
-                           int pitch = (width * bytes_per_pixel + 3) & ~3;
-
-                           int buffer_bytes = color_table_size * 3 + pitch * 
height;
-                           Uint8*      buffer = new Uint8[buffer_bytes];
-
-                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-
-                           Uint8*      color_table = buffer;
-
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_in_row = buffer + 
color_table_size * 3 + j * pitch;
-                                   Uint8*      image_out_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint8       pixel = image_in_row[i 
* bytes_per_pixel];
-                                           image_out_row[i * 3 + 0] = 
color_table[pixel * 3 + 0];
-                                           image_out_row[i * 3 + 1] = 
color_table[pixel * 3 + 1];
-                                           image_out_row[i * 3 + 2] = 
color_table[pixel * 3 + 2];
-                                       }
-                               }
-
-                           delete [] buffer;
-                       }
-                   else if (bitmap_format == 4)
-                       {
-                           // 16 bits / pixel
-                           const int   bytes_per_pixel = 2;
-                           int pitch = (width * bytes_per_pixel + 3) & ~3;
-
-                           int buffer_bytes = pitch * height;
-                           Uint8*      buffer = new Uint8[buffer_bytes];
-
-                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-                       
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_in_row = buffer + j * 
pitch;
-                                   Uint8*      image_out_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint16      pixel = image_in_row[i 
* 2] | (image_in_row[i * 2 + 1] << 8);
-                                       
-                                           // @@ How is the data packed???  
I'm just guessing here that it's 565!
-                                           image_out_row[i * 3 + 0] = (pixel 
>> 8) & 0xF8;     // red
-                                           image_out_row[i * 3 + 1] = (pixel 
>> 3) & 0xFC;     // green
-                                           image_out_row[i * 3 + 2] = (pixel 
<< 3) & 0xF8;     // blue
-                                       }
-                               }
-                       
-                           delete [] buffer;
-                       }
-                   else if (bitmap_format == 5)
-                       {
-                           // 32 bits / pixel, input is ARGB format (???)
-                           const int   bytes_per_pixel = 4;
-                           int pitch = width * bytes_per_pixel;
-
-                           int buffer_bytes = pitch * height;
-                           Uint8*      buffer = new Uint8[buffer_bytes];
-
-                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-                       
-                           // Need to re-arrange ARGB into RGB.
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_in_row = buffer + j * 
pitch;
-                                   Uint8*      image_out_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint8       a = image_in_row[i * 4 
+ 0];
-                                           Uint8       r = image_in_row[i * 4 
+ 1];
-                                           Uint8       g = image_in_row[i * 4 
+ 2];
-                                           Uint8       b = image_in_row[i * 4 
+ 3];
-                                           image_out_row[i * 3 + 0] = r;
-                                           image_out_row[i * 3 + 1] = g;
-                                           image_out_row[i * 3 + 2] = b;
-                                           a = a;      // Inhibit warning.
-                                       }
-                               }
-
-                           delete [] buffer;
-                       }
-
-//                             bitmap_character*       ch = new 
bitmap_character(image);
-                   bi = render::create_bitmap_info_rgb(image);
-                   delete image;
-
-//                             // add image to movie, under character id.
-//                             m->add_bitmap_character(character_id, ch);
-               }
-           else
-               {
-                   // RGBA image data.
-                   assert(tag_type == 36);
-
-                   image::rgba*        image = image::create_rgba(width, 
height);
-
-                   if (bitmap_format == 3)
-                       {
-                           // 8-bit data, preceded by a palette.
-
-                           const int   bytes_per_pixel = 1;
-                           int color_table_size = in->read_u8();
-                           color_table_size += 1;      // !! SWF stores one 
less than the actual size
-
-                           int pitch = (width * bytes_per_pixel + 3) & ~3;
-
-                           int buffer_bytes = color_table_size * 4 + pitch * 
height;
-                           Uint8*      buffer = new Uint8[buffer_bytes];
-
-                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-
-                           Uint8*      color_table = buffer;
-
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_in_row = buffer + 
color_table_size * 4 + j * pitch;
-                                   Uint8*      image_out_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint8       pixel = image_in_row[i 
* bytes_per_pixel];
-                                           image_out_row[i * 4 + 0] = 
color_table[pixel * 4 + 0];
-                                           image_out_row[i * 4 + 1] = 
color_table[pixel * 4 + 1];
-                                           image_out_row[i * 4 + 2] = 
color_table[pixel * 4 + 2];
-                                           image_out_row[i * 4 + 3] = 
color_table[pixel * 4 + 3];
-                                       }
-                               }
-
-                           delete [] buffer;
-                       }
-                   else if (bitmap_format == 4)
-                       {
-                           // 16 bits / pixel
-                           const int   bytes_per_pixel = 2;
-                           int pitch = (width * bytes_per_pixel + 3) & ~3;
-
-                           int buffer_bytes = pitch * height;
-                           Uint8*      buffer = new Uint8[buffer_bytes];
-
-                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-                       
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_in_row = buffer + j * 
pitch;
-                                   Uint8*      image_out_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint16      pixel = image_in_row[i 
* 2] | (image_in_row[i * 2 + 1] << 8);
-                                       
-                                           // @@ How is the data packed???  
I'm just guessing here that it's 565!
-                                           image_out_row[i * 4 + 0] = 255;     
                // alpha
-                                           image_out_row[i * 4 + 1] = (pixel 
>> 8) & 0xF8;     // red
-                                           image_out_row[i * 4 + 2] = (pixel 
>> 3) & 0xFC;     // green
-                                           image_out_row[i * 4 + 3] = (pixel 
<< 3) & 0xF8;     // blue
-                                       }
-                               }
-                       
-                           delete [] buffer;
-                       }
-                   else if (bitmap_format == 5)
-                       {
-                           // 32 bits / pixel, input is ARGB format
-
-                           inflate_wrapper(in->get_underlying_stream(), 
image->m_data, width * height * 4);
-                           assert(in->get_position() <= 
in->get_tag_end_position());
-                       
-                           // Need to re-arrange ARGB into RGBA.
-                           for (int j = 0; j < height; j++)
-                               {
-                                   Uint8*      image_row = 
image::scanline(image, j);
-                                   for (int i = 0; i < width; i++)
-                                       {
-                                           Uint8       a = image_row[i * 4 + 
0];
-                                           Uint8       r = image_row[i * 4 + 
1];
-                                           Uint8       g = image_row[i * 4 + 
2];
-                                           Uint8       b = image_row[i * 4 + 
3];
-                                           image_row[i * 4 + 0] = r;
-                                           image_row[i * 4 + 1] = g;
-                                           image_row[i * 4 + 2] = b;
-                                           image_row[i * 4 + 3] = a;
-                                       }
-                               }
-                       }
-
-                   bi = render::create_bitmap_info_rgba(image);
-//                             bitmap_character*       ch = new 
bitmap_character(image);
-                   delete image;
-
-//                             // add image to movie, under character id.
-//                             m->add_bitmap_character(character_id, ch);
-               }
-#endif // TU_CONFIG_LINK_TO_ZLIB
-       }
-    else
-       {
-           bi = render::create_bitmap_info_empty();
-       }
-    assert(bi->get_ref_count() == 0);
-
-    bitmap_character*  ch = new bitmap_character(bi);
-
-    // add image to movie, under character id.
-    m->add_bitmap_character(character_id, ch);
-}
-
-
-void   define_shape_loader(stream* in, int tag_type, movie_definition_sub* m)
-{
-    assert(tag_type == 2
-          || tag_type == 22
-          || tag_type == 32);
-
-    Uint16     character_id = in->read_u16();
-    IF_VERBOSE_PARSE(log_msg("  shape_loader: id = %d\n", character_id));
-
-    shape_character_def*       ch = new shape_character_def;
-    ch->read(in, tag_type, true, m);
-
-    IF_VERBOSE_PARSE(log_msg("  bound rect:"); ch->get_bound().print());
-
-    m->add_character(character_id, ch);
-}
-
-void define_shape_morph_loader(stream* in, int tag_type, movie_definition_sub* 
m)
-{
-    assert(tag_type == 46);
-    Uint16 character_id = in->read_u16();
-    IF_VERBOSE_PARSE(log_msg("  shape_morph_loader: id = %d\n", character_id));
-    morph2_character_def* morph = new morph2_character_def;
-    morph->read(in, tag_type, true, m);
-    m->add_character(character_id, morph);
-}
-
-//
-// font loaders
-//
-
-
-void   define_font_loader(stream* in, int tag_type, movie_definition_sub* m)
-    // Load a DefineFont or DefineFont2 tag.
-{
-    assert(tag_type == 10 || tag_type == 48);
-
-    Uint16     font_id = in->read_u16();
-               
-    font*      f = new font;
-    f->read(in, tag_type, m);
-
-    m->add_font(font_id, f);
-
-    // Automatically keeping fonts in fontlib is
-    // problematic.  The app should be responsible for
-    // optionally adding fonts to fontlib.
-    // //fontlib::add_font(f);
-}
-
-
-void   define_font_info_loader(stream* in, int tag_type, movie_definition_sub* 
m)
-    // Load a DefineFontInfo tag.  This adds information to an
-    // existing font.
-{
-    assert(tag_type == 13);
-
-    Uint16     font_id = in->read_u16();
-               
-    font*      f = m->get_font(font_id);
-    if (f)
-       {
-           f->read_font_info(in);
-       }
-    else
-       {
-           log_error("define_font_info_loader: can't find font w/ id %d\n", 
font_id);
-       }
-}
-
-
-//
-// swf_event
-//
-// For embedding event handlers in place_object_2
-
-
-struct swf_event
-{
-    // NOTE: DO NOT USE THESE AS VALUE TYPES IN AN
-    // array<>!  They cannot be moved!  The private
-    // operator=(const swf_event&) should help guard
-    // against that.
-
-    event_id   m_event;
-    action_buffer      m_action_buffer;
-    as_value   m_method;
-
-    swf_event()
-       {
-       }
-
-    void       attach_to(character* ch) const
-       {
-           ch->set_event_handler(m_event, m_method);
-       }
-
-    void       read(stream* in, Uint32 flags)
-       {
-           assert(flags != 0);
-
-           // Scream if more than one bit is set, since we're not set up to 
handle
-           // that, and it doesn't seem possible to express in ActionScript 
source,
-           // so it's important to know if this ever occurs in the wild.
-           if (flags & (flags - 1))
-               {
-                   log_error("error: swf_event::read() -- more than one event 
type encoded!  "
-                             "unexpected! flags = 0x%x\n", flags);
-               }
-
-           // 14 bits reserved, 18 bits used
-
-           static const event_id       s_code_bits[18] =
-               {
-                   event_id::LOAD,
-                   event_id::ENTER_FRAME,
-                   event_id::UNLOAD,
-                   event_id::MOUSE_MOVE,
-                   event_id::MOUSE_DOWN,
-                   event_id::MOUSE_UP,
-                   event_id::KEY_DOWN,
-                   event_id::KEY_UP,
-                   event_id::DATA,
-                   event_id::INITIALIZE,
-                   event_id::PRESS,
-                   event_id::RELEASE,
-                   event_id::RELEASE_OUTSIDE,
-                   event_id::ROLL_OVER,
-                   event_id::ROLL_OUT,
-                   event_id::DRAG_OVER,
-                   event_id::DRAG_OUT,
-               };
-
-           // Let's see if the event flag we received is for an event that we 
know of
-           if ((pow(2,int(sizeof(s_code_bits)/sizeof(s_code_bits[0])))-1) < 
flags)
-               {
-                   log_error("error: swf_event::read() -- unknown / unhandled 
event type received, flags = 0x%x\n", flags);
-               }
-
-           for (int i = 0, mask = 1; i < 
int(sizeof(s_code_bits)/sizeof(s_code_bits[0])); i++, mask <<= 1)
-               {
-                   if (flags & mask)
-                       {
-                           m_event = s_code_bits[i];
-                           break;
-                       }
-               }
-
-           // what to do w/ key_press???  Is the data in the reserved parts of 
the flags???
-           if (flags & (1 << 17))
-               {
-                   log_error("swf_event::read -- KEY_PRESS found, not handled 
yet, flags = 0x%x\n", flags);
-               }
-
-           Uint32      event_length = in->read_u32();
-           UNUSED(event_length);
-
-           // Read the actions.
-           IF_VERBOSE_ACTION(log_msg("---- actions for event %s\n", 
m_event.get_function_name().c_str()));
-           m_action_buffer.read(in);
-
-           if (m_action_buffer.get_length() != (int) event_length)
-               {
-                   log_error("error -- swf_event::read(), event_length = %d, 
but read %d\n",
-                             event_length,
-                             m_action_buffer.get_length());
-                   // @@ discard this event handler??
-               }
-
-           // Create a function to execute the actions.
-           array<with_stack_entry>     empty_with_stack;
-           as_as_function*     func = new as_as_function(&m_action_buffer, 
NULL, 0, empty_with_stack);
-           func->set_length(m_action_buffer.get_length());
-
-           m_method.set_as_as_function(func);
-       }
-
-private:
-    // DON'T USE THESE
-    swf_event(const swf_event& s) { assert(0); }
-    void       operator=(const swf_event& s) { assert(0); }
-};
-
-
-//
-// place_object_2
-//
-       
-struct place_object_2 : public execute_tag
-{
-    int        m_tag_type;
-    char*      m_name;
-    float      m_ratio;
-    cxform     m_color_transform;
-    matrix     m_matrix;
-    bool       m_has_matrix;
-    bool       m_has_cxform;
-    Uint16     m_depth;
-    Uint16     m_character_id;
-    Uint16     m_clip_depth;
-    enum place_type {
-       PLACE,
-       MOVE,
-       REPLACE,
-    } m_place_type;
-    array<swf_event*>  m_event_handlers;
-
-
-    place_object_2()
-       :
-       m_tag_type(0),
-       m_name(NULL),
-       m_ratio(0),
-       m_has_matrix(false),
-       m_has_cxform(false),
-       m_depth(0),
-       m_character_id(0),
-       m_clip_depth(0),
-       m_place_type(PLACE)
-       {
-       }
-
-    ~place_object_2()
-       {
-           delete [] m_name;
-           m_name = NULL;
-
-           for (int i = 0, n = m_event_handlers.size(); i < n; i++)
-               {
-                   delete m_event_handlers[i];
-               }
-           m_event_handlers.resize(0);
-       }
-
-    void       read(stream* in, int tag_type, int movie_version)
-       {
-           assert(tag_type == 4 || tag_type == 26);
-
-           m_tag_type = tag_type;
-
-           if (tag_type == 4)
-               {
-                   // Original place_object tag; very simple.
-                   m_character_id = in->read_u16();
-                   m_depth = in->read_u16();
-                   m_matrix.read(in);
-
-                   IF_VERBOSE_PARSE(
-                       log_msg("  char_id = %d\n"
-                               "  depth = %d\n"
-                               "  mat = \n",
-                               m_character_id,
-                               m_depth);
-                       m_matrix.print());
-
-                   if (in->get_position() < in->get_tag_end_position())
-                       {
-                           m_color_transform.read_rgb(in);
-                           IF_VERBOSE_PARSE(log_msg("  cxform:\n"); 
m_color_transform.print());
-                       }
-               }
-           else if (tag_type == 26)
-               {
-                   in->align();
-
-                   bool        has_actions = in->read_uint(1) ? true : false;
-                   bool        has_clip_bracket = in->read_uint(1) ? true : 
false;
-                   bool        has_name = in->read_uint(1) ? true : false;
-                   bool        has_ratio = in->read_uint(1) ? true : false;
-                   bool        has_cxform = in->read_uint(1) ? true : false;
-                   bool        has_matrix = in->read_uint(1) ? true : false;
-                   bool        has_char = in->read_uint(1) ? true : false;
-                   bool        flag_move = in->read_uint(1) ? true : false;
-
-                   m_depth = in->read_u16();
-                   IF_VERBOSE_PARSE(log_msg("  depth = %d\n", m_depth));
-
-                   if (has_char) {
-                       m_character_id = in->read_u16();
-                       IF_VERBOSE_PARSE(log_msg("  char id = %d\n", 
m_character_id));
-                   }
-
-                   if (has_matrix) {
-                       m_has_matrix = true;
-                       m_matrix.read(in);
-                       IF_VERBOSE_PARSE(log_msg("  mat:\n"); m_matrix.print());
-                   }
-                   if (has_cxform) {
-                       m_has_cxform = true;
-                       m_color_transform.read_rgba(in);
-                       IF_VERBOSE_PARSE(log_msg("  cxform:\n"); 
m_color_transform.print());
-                   }
-                               
-                   if (has_ratio) {
-                       m_ratio = (float)in->read_u16() / (float)65535;
-                       IF_VERBOSE_PARSE(log_msg("  ratio: %f\n", m_ratio));
-                   }
-                               
-                   if (has_name) {
-                       m_name = in->read_string();
-                       IF_VERBOSE_PARSE(log_msg("  name = %s\n", m_name ? 
m_name : "<null>"));
-                   }
-                   if (has_clip_bracket) {
-                       m_clip_depth = in->read_u16(); 
-                       IF_VERBOSE_PARSE(log_msg("  clip_depth = %d\n", 
m_clip_depth));
-                   }
-                   if (has_actions)
-                       {
-                           Uint16      reserved = in->read_u16();
-                           UNUSED(reserved);
-
-                           // The logical 'or' of all the following handlers.
-                           // I don't think we care about this...
-                           Uint32      all_flags = 0;
-                           if (movie_version >= 6)
-                               {
-                                   all_flags = in->read_u32();
-                               }
-                           else
-                               {
-                                   all_flags = in->read_u16();
-                               }
-                           UNUSED(all_flags);
-
-                           IF_VERBOSE_PARSE(log_msg("  actions: flags = 
0x%X\n", all_flags));
-
-                           // Read swf_events.
-                           for (;;)
-                               {
-                                   // Read event.
-                                   in->align();
-
-                                   Uint32      this_flags = 0;
-                                   if (movie_version >= 6)
-                                       {
-                                           this_flags = in->read_u32();
-                                       }
-                                   else
-                                       {
-                                           this_flags = in->read_u16();
-                                       }
-
-                                   if (this_flags == 0)
-                                       {
-                                           // Done with events.
-                                           break;
-                                       }
-
-                                   swf_event*  ev = new swf_event;
-                                   ev->read(in, this_flags);
-
-                                   m_event_handlers.push_back(ev);
-                               }
-                       }
-
-
-                   if (has_char == true && flag_move == true)
-                       {
-                           // Remove whatever's at m_depth, and put 
m_character there.
-                           m_place_type = REPLACE;
-                       }
-                   else if (has_char == false && flag_move == true)
-                       {
-                           // Moves the object at m_depth to the new location.
-                           m_place_type = MOVE;
-                       }
-                   else if (has_char == true && flag_move == false)
-                       {
-                           // Put m_character at m_depth.
-                           m_place_type = PLACE;
-                       }
-                                
-                   //log_msg("place object at depth %i\n", m_depth);
-               }
-       }
-
-               
-    void       execute(movie* m)
-       // Place/move/whatever our object in the given movie.
-       {
-           switch (m_place_type) {
-             case PLACE:
-                 m->add_display_object(
-                     m_character_id,
-                     m_name,
-                     m_event_handlers,
-                     m_depth,
-                     m_tag_type != 4,  // original place_object doesn't do 
replacement
-                     m_color_transform,
-                     m_matrix,
-                     m_ratio,
-                     m_clip_depth);
-                 break;
-                 
-             case MOVE:
-                 m->move_display_object(
-                     m_depth,
-                     m_has_cxform,
-                     m_color_transform,
-                     m_has_matrix,
-                     m_matrix,
-                     m_ratio,
-                     m_clip_depth);
-                 break;
-                 
-             case REPLACE:
-                 m->replace_display_object(
-                     m_character_id,
-                     m_name,
-                     m_depth,
-                     m_has_cxform,
-                     m_color_transform,
-                     m_has_matrix,
-                     m_matrix,
-                     m_ratio,
-                     m_clip_depth);
-                 break;
-           }
-       }
-    
-    void       execute_state(movie* m)
-       {
-           execute(m);
-       }
-    
-    void       execute_state_reverse(movie* m, int frame)
-       {
-           switch (m_place_type) {
-             case PLACE:
-                 // reverse of add is remove
-                 m->remove_display_object(m_depth, m_tag_type == 4 ? 
m_character_id : -1);
-                 break;
-                 
-             case MOVE:
-                 // reverse of move is move
-                 m->move_display_object(
-                     m_depth,
-                     m_has_cxform,
-                     m_color_transform,
-                     m_has_matrix,
-                     m_matrix,
-                     m_ratio,
-                     m_clip_depth);
-                 break;
-                 
-             case REPLACE:
-             {
-                 // reverse of replace is to re-add the previous object.
-                 execute_tag*  last_add = 
m->find_previous_replace_or_add_tag(frame, m_depth, -1);
-                 if (last_add) {
-                     last_add->execute_state(m);
-                 } else {
-                     log_error("reverse REPLACE can't find previous replace or 
add tag(%d, %d)\n",
-                               frame, m_depth);
-                     
-                 }
-                 break;
-             }
-           }
-       }
-    
-    virtual uint32     get_depth_id_of_replace_or_add_tag() const
-       // "depth_id" is the 16-bit depth & id packed into one 32-bit int.
-       {
-           if (m_place_type == PLACE || m_place_type == REPLACE)
-               {
-                   int id = -1;
-                   if (m_tag_type == 4)
-                       {
-                           // Old-style PlaceObject; the corresponding Remove
-                           // is specific to the character_id.
-                           id = m_character_id;
-                       }
-                   return ((m_depth & 0x0FFFF) << 16) | (id & 0x0FFFF);
-               }
-           else
-               {
-                   return (uint32) -1;
-               }
-       }
-};
-
-
-       
-void   place_object_2_loader(stream* in, int tag_type, movie_definition_sub* m)
-{
-    assert(tag_type == 4 || tag_type == 26);
-
-    IF_VERBOSE_PARSE(log_msg("  place_object_2\n"));
-
-    place_object_2*    ch = new place_object_2;
-    ch->read(in, tag_type, m->get_version());
-
-    m->add_execute_tag(ch);
+    m->add_bitmap_character(character_id, ch);
 }
 
 
-//
-// sprite_definition
-//
-
-
-// A sprite is a mini movie-within-a-movie.  It doesn't define
-// its own characters; it uses the characters from the parent
-// movie, but it has its own frame counter, display list, etc.
-//
-// The sprite implementation is divided into a
-// sprite_definition and a sprite_instance.  The _definition
-// holds the immutable data for a sprite, while the _instance
-// contains the state for a specific instance being updated
-// and displayed in the parent movie's display list.
-
-
-struct sprite_definition : public movie_definition_sub
-{
-    movie_definition_sub*           m_movie_def;               // parent movie.
-    array<array<execute_tag*> >  m_playlist;   // movie control events for 
each frame.
-    stringi_hash<int>       m_named_frames;    // stores 0-based frame #'s
-    int                             m_frame_count;
-    int                             m_loading_frame;
-    sprite_definition(movie_definition_sub* m)
-       :
-       m_movie_def(m),
-       m_frame_count(0),
-       m_loading_frame(0)
-       {
-           assert(m_movie_def);
-       }
-
-    ~sprite_definition()
-       {
-           // Release our playlist data.
-           {for (int i = 0, n = m_playlist.size(); i < n; i++)
-               {
-                   for (int j = 0, m = m_playlist[i].size(); j < m; j++)
-                       {
-                           delete m_playlist[i][j];
-                       }
-               }}
-       }
-
-    // overloads from movie_definition
-    virtual float      get_width_pixels() const { return 1; }
-    virtual float      get_height_pixels() const { return 1; }
-    virtual int        get_frame_count() const { return m_frame_count; }
-    virtual float      get_frame_rate() const { return 
m_movie_def->get_frame_rate(); }
-    virtual int        get_loading_frame() const { return m_loading_frame; }
-    virtual int        get_version() const { return 
m_movie_def->get_version(); }
-    virtual void       add_character(int id, character_def* ch) { 
log_error("add_character tag appears in sprite tags!\n"); }
-    virtual void       add_font(int id, font* ch) { log_error("add_font tag 
appears in sprite tags!\n"); }
-    virtual font*      get_font(int id) { return m_movie_def->get_font(id); }
-    virtual void       set_jpeg_loader(jpeg::input* j_in) { assert(0); }
-    virtual jpeg::input*       get_jpeg_loader() { return NULL; }
-    virtual bitmap_character_def*      get_bitmap_character(int id) { return 
m_movie_def->get_bitmap_character(id); }
-    virtual void       add_bitmap_character(int id, bitmap_character_def* ch) 
{ log_error("add_bc appears in sprite tags!\n"); }
-    virtual sound_sample*      get_sound_sample(int id) { return 
m_movie_def->get_sound_sample(id); }
-    virtual void       add_sound_sample(int id, sound_sample* sam) { 
log_error("add sam appears in sprite tags!\n"); }
-
-    // @@ would be nicer to not inherit these...
-    virtual create_bitmaps_flag        get_create_bitmaps() const { assert(0); 
return DO_LOAD_BITMAPS; }
-    virtual create_font_shapes_flag    get_create_font_shapes() const { 
assert(0); return DO_LOAD_FONT_SHAPES; }
-    virtual int        get_bitmap_info_count() const { assert(0); return 0; }
-    virtual bitmap_info*       get_bitmap_info(int i) const { assert(0); 
return NULL; }
-    virtual void       add_bitmap_info(bitmap_info* bi) { assert(0); }
-
-    virtual void       export_resource(const tu_string& symbol, resource* res) 
{ log_error("can't export from sprite\n"); }
-    virtual smart_ptr<resource>        get_exported_resource(const tu_string& 
sym) { return m_movie_def->get_exported_resource(sym); }
-    virtual void       add_import(const char* source_url, int id, const char* 
symbol) { assert(0); }
-    virtual void       visit_imported_movies(import_visitor* v) { assert(0); }
-    virtual void       resolve_import(const char* source_url, 
movie_definition* d) { assert(0); }
-    virtual character_def*     get_character_def(int id)
-       {
-           return m_movie_def->get_character_def(id);
-       }
-    virtual void       generate_font_bitmaps() { assert(0); }
-
-
-    virtual void       output_cached_data(tu_file* out, const cache_options& 
options)
-       {
-           // Nothing to do.
-           return;
-       }
-    virtual void       input_cached_data(tu_file* in)
-       {
-           // Nothing to do.
-           return;
-       }
-
-    virtual movie_interface*   create_instance()
-       {
-           return NULL;
-       }
-
-    // overloads from character_def
-    virtual character* create_character_instance(movie* parent, int id);
-
-
-    /* sprite_definition */
-    virtual void       add_execute_tag(execute_tag* c)
-       {
-           m_playlist[m_loading_frame].push_back(c);
-       }
-
-    /* sprite_definition */
-    virtual void       add_init_action(int sprite_id, execute_tag* c)
-       {
-           // Sprite def's should not have do_init_action tags in them!  (@@ 
correct?)
-           log_error("sprite_definition::add_init_action called!  Ignored.\n");
-       }
-
-    /* sprite_definition */
-    virtual void       add_frame_name(const char* name)
-       // Labels the frame currently being loaded with the
-       // given name.  A copy of the name string is made and
-       // kept in this object.
-       {
-           assert(m_loading_frame >= 0 && m_loading_frame < m_frame_count);
-
-           tu_string   n = name;
-           int currently_assigned = 0;
-           if (m_named_frames.get(n, &currently_assigned) == true)
-               {
-                   log_error("add_frame_name(%d, '%s') -- frame name already 
assigned to frame %d; overriding\n",
-                             m_loading_frame,
-                             name,
-                             currently_assigned);
-               }
-           m_named_frames.set(n, m_loading_frame);     // stores 0-based frame 
#
-       }
-
-    /* sprite_definition */
-    bool       get_labeled_frame(const char* label, int* frame_number)
-       // Returns 0-based frame #
-       {
-           return m_named_frames.get(label, frame_number);
-       }
-
-    const array<execute_tag*>& get_playlist(int frame_number)
-       // frame_number is 0-based
-       {
-           return m_playlist[frame_number];
-       }
-
-    /* sprite_definition */
-    virtual const array<execute_tag*>* get_init_actions(int frame_number)
-       {
-           // Sprites do not have init actions in their
-           // playlists!  Only the root movie
-           // (movie_def_impl) does (@@ correct?)
-           return NULL;
-       }
-
-
-    /* sprite_definition */
-    void       read(stream* in)
-       // Read the sprite info.  Consists of a series of tags.
-       {
-           int tag_end = in->get_tag_end_position();
-
-           m_frame_count = in->read_u16();
-           // ALEX: some SWF files have been seen that have 0-frame sprites.
-           // The Macromedia player behaves as if they have 1 frame.
-           if (m_frame_count < 1)
-               {
-                   m_frame_count = 1;
-               }
-           m_playlist.resize(m_frame_count);   // need a playlist for each 
frame
-
-           IF_VERBOSE_PARSE(log_msg("  frames = %d\n", m_frame_count));
-
-           m_loading_frame = 0;
-
-           while ((Uint32) in->get_position() < (Uint32) tag_end)
-               {
-                   int tag_type = in->open_tag();
-                   loader_function lf = NULL;
-                   if (tag_type == 1)
-                       {
-                           // show frame tag -- advance to the next frame.
-                           IF_VERBOSE_PARSE(log_msg("  show_frame 
(sprite)\n"));
-                           m_loading_frame++;
-                       }
-                   else if (s_tag_loaders.get(tag_type, &lf))
-                       {
-                           // call the tag loader.  The tag loader should add
-                           // characters or tags to the movie data structure.
-                           (*lf)(in, tag_type, this);
-                       }
-                   else
-                       {
-                           // no tag loader for this tag type.
-                           IF_VERBOSE_PARSE(log_msg("*** no tag loader for 
type %d\n", tag_type));
-                       }
-
-                   in->close_tag();
-               }
-
-           IF_VERBOSE_PARSE(log_msg("  -- sprite END --\n"));
-       }
-};
-
-
-//
-// sprite_instance
-//
-
-
-struct sprite_instance : public character
+void   define_bits_jpeg2_loader(stream* in, int tag_type, 
movie_definition_sub* m)
 {
-    smart_ptr<movie_definition_sub>    m_def;
-    movie_root*        m_root;
-
-    display_list       m_display_list;
-    array<action_buffer*>      m_action_list;
-
-    play_state m_play_state;
-    int                m_current_frame;
-    float              m_time_remainder;
-    bool               m_update_frame;
-    bool               m_has_looped;
-    bool               m_accept_anim_moves;    // once we've been moved by 
ActionScript, don't accept moves from anim tags.
-    array<bool>        m_init_actions_executed;        // a bit-array class 
would be ideal for this
-
-    as_environment     m_as_environment;
-
-    enum mouse_state
-    {
-       UP = 0,
-       DOWN,
-       OVER
-    };
-    mouse_state m_mouse_state;
-
-    sprite_instance(movie_definition_sub* def, movie_root* r, movie* parent, 
int id)
-       :
-       character(parent, id),
-       m_def(def),
-       m_root(r),
-       m_play_state(PLAY),
-       m_current_frame(0),
-       m_time_remainder(0),
-       m_update_frame(true),
-       m_has_looped(false),
-       m_accept_anim_moves(true),
-       m_mouse_state(UP)
-       {
-           assert(m_def != NULL);
-           assert(m_root != NULL);
-                       
-           //m_root->add_ref();        // @@ circular!
-           m_as_environment.set_target(this);
-
-           sprite_builtins_init();
-
-           // Initialize the flags for init action executed.
-           m_init_actions_executed.resize(m_def->get_frame_count());
-           memset(&m_init_actions_executed[0], 0,
-                  sizeof(m_init_actions_executed[0]) * 
m_init_actions_executed.size());
-       }
-
-    // sprite instance of add_interval_handler()
-    virtual int    add_interval_timer(void *timer)
-       {
-           // log_msg("FIXME: %s:\n", __FUNCTION__);
-           return m_root->add_interval_timer(timer);
-       }
-
-    virtual void    clear_interval_timer(int x)
-       {
-           // log_msg("FIXME: %s:\n", __FUNCTION__);
-           m_root->clear_interval_timer(x);
-       }
-       
-
-    /* sprite_instance */
-    virtual void    do_something(void *timer)
-       {
-           as_value    val;
-           as_object      *obj, *this_ptr;
-           as_environment *as_env;
-
-           //printf("FIXME: %s:\n", __FUNCTION__);
-           Timer *ptr = (Timer *)timer;
-           //log_msg("INTERVAL ID is %d\n", ptr->getIntervalID());
-
-           const as_value&     timer_method = ptr->getASFunction();
-           as_env = ptr->getASEnvironment();
-           this_ptr = ptr->getASObject();
-           obj = ptr->getObject();
-           //m_as_environment.push(obj);
-                       
-           as_c_function_ptr   cfunc = timer_method.to_c_function();
-           if (cfunc) {
-               // It's a C function. Call it.
-               //log_msg("Calling C function for interval timer\n");
-               //(*cfunc)(&val, obj, as_env, 0, 0);
-               (*cfunc)(fn_call(&val, obj, &m_as_environment, 0, 0));
-                               
-           } else if (as_as_function* as_func = timer_method.to_as_function()) 
{
-               // It's an ActionScript function. Call it.
-               as_value method;
-               //log_msg("Calling ActionScript function for interval timer\n");
-               (*as_func)(fn_call(&val, (as_object_interface *)this_ptr, 
as_env, 0, 0));
-               //(*as_func)(&val, (as_object_interface *)this_ptr, 
&m_as_environment, 1, 1);
-           } else {
-               log_error("error in call_method(): method is not a function\n");
-           }    
-       }       
-
-    virtual ~sprite_instance()
-       {
-           m_display_list.clear();
-           //m_root->drop_ref();
-       }
-
-    movie_interface*   get_root_interface() { return m_root; }
-    movie_root*        get_root() { return m_root; }
-    movie*     get_root_movie() { return m_root->get_root_movie(); }
-
-    movie_definition*  get_movie_definition() { return m_def.get_ptr(); }
-
-    float      get_width()
-       {
-           float       w = 0;
-           int i, n = m_display_list.get_character_count();
-           character* ch;
-           for (i = 0; i < n; i++)
-               {
-                   ch = m_display_list.get_character(i);
-                   if (ch != NULL)
-                       {
-                           float ch_w = ch->get_width();
-                           if (ch_w > w)
-                               {
-                                   w = ch_w;
-                               }
-                       }
-               }
-
-           return w;
-       }
-
-
-    float      get_height()
-       {
-           float       h = 0; 
-           int i, n = m_display_list.get_character_count();
-           character* ch;
-           for (i=0; i < n; i++)
-               {
-                   ch = m_display_list.get_character(i);
-                   if (ch != NULL)
-                       {
-                           float       ch_h = ch->get_height();
-                           if (ch_h > h)
-                               {
-                                   h = ch_h;
-                               }
-                       }
-               }
-           return h;
-       }
-
-    int        get_current_frame() const { return m_current_frame; }
-    int        get_frame_count() const { return m_def->get_frame_count(); }
-
-    void       set_play_state(play_state s)
-       // Stop or play the sprite.
-       {
-           if (m_play_state != s)
-               {
-                   m_time_remainder = 0;
-               }
-
-           m_play_state = s;
-       }
-    play_state get_play_state() const { return m_play_state; }
-
-
-    character* get_character(int character_id)
-       {
-//                     return m_def->get_character_def(character_id);
-           // @@ TODO -- look through our dlist for a match
-           return NULL;
-       }
-
-    float      get_background_alpha() const
-       {
-           // @@ this doesn't seem right...
-           return m_root->get_background_alpha();
-       }
-
-    float      get_pixel_scale() const { return m_root->get_pixel_scale(); }
-
-    virtual void       get_mouse_state(int* x, int* y, int* buttons)
-       {
-           m_root->get_mouse_state(x, y, buttons);
-       }
-
-    void       set_background_color(const rgba& color)
-       {
-           m_root->set_background_color(color);
-       }
-
-    float      get_timer() const { return m_root->get_timer(); }
-
-    void       restart()
-       {
-           m_current_frame = 0;
-           m_time_remainder = 0;
-           m_update_frame = true;
-           m_has_looped = false;
-           m_play_state = PLAY;
-
-           execute_frame_tags(m_current_frame);
-           m_display_list.update();
-       }
-
-
-    virtual bool       has_looped() const { return m_has_looped; }
-
-    virtual bool       get_accept_anim_moves() const { return 
m_accept_anim_moves; }
-
-    inline int transition(int a, int b) const
-       // Combine the flags to avoid a conditional. It would be faster with a 
macro.
-       {
-           return (a << 2) | b;
-       }
-
-
-    bool can_handle_mouse_event()
-       // Return true if we have any mouse event handlers.
-       {
-           // We should cache this!
-           as_value dummy;
-
-           // Functions that qualify as mouse event handlers.
-           const char* FN_NAMES[] = {
-               "onKeyPress",
-               "onRelease",
-               "onDragOver",
-               "onDragOut",
-               "onPress",
-               "onReleaseOutside",
-               "onRollout",
-               "onRollover",
-           };
-           for (unsigned int i = 0; i < ARRAYSIZE(FN_NAMES); i++) {
-               if (get_member(FN_NAMES[i], &dummy)) {
-                   return true;
-               }
-           }
+    assert(tag_type == 21);
+               
+    Uint16     character_id = in->read_u16();
 
-           // Event handlers that qualify as mouse event handlers.
-           const event_id::id_code EH_IDS[] = {
-               event_id::PRESS,
-               event_id::RELEASE,
-               event_id::RELEASE_OUTSIDE,
-               event_id::ROLL_OVER,
-               event_id::ROLL_OUT,
-               event_id::DRAG_OVER,
-               event_id::DRAG_OUT,
-           };
-           {for (unsigned int i = 0; i < ARRAYSIZE(EH_IDS); i++) {
-               if (get_event_handler(EH_IDS[i], &dummy)) {
-                   return true;
-               }
-           }}
+    IF_VERBOSE_PARSE(log_msg("  define_bits_jpeg2_loader: charid = %d pos = 
0x%x\n", character_id, in->get_position()));
 
-           return false;
-       }
+    //
+    // Read the image data.
+    //
                
+    bitmap_info*       bi = NULL;
 
-    /* sprite_instance */
-    virtual movie*     get_topmost_mouse_entity(float x, float y)
-       // Return the topmost entity that the given point
-       // covers that can receive mouse events.  NULL if
-       // none.  Coords are in parent's frame.
+    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
        {
-           if (get_visible() == false) {
-               return NULL;
-           }
-
-           matrix      m = get_matrix();
-           point       p;
-           m.transform_by_inverse(&p, point(x, y));
-
-           int i, n = m_display_list.get_character_count();
-           // Go backwards, to check higher objects first.
-           for (i = n - 1; i >= 0; i--)
-               {
-                   character* ch = m_display_list.get_character(i);
-                               
-                   if (ch != NULL && ch->get_visible())
-                       {
-                           movie*      te = 
ch->get_topmost_mouse_entity(p.m_x, p.m_y);
-                           if (te)
-                               {
-                                   // The containing entity that 1) is closest 
to root and 2) can
-                                   // handle mouse events takes precedence.
-                                   if (can_handle_mouse_event()) {
-                                       return this;
-                                   } else {
-                                       return te;
-                                   }
-                               }
-                       }
-               }
-
-           return NULL;
+#if TU_CONFIG_LINK_TO_JPEGLIB
+           image::rgb* im = image::read_swf_jpeg2(in->get_underlying_stream());
+           bi = render::create_bitmap_info_rgb(im);
+           delete im;
+#else
+           log_error("gnash is not linked to jpeglib -- can't load jpeg image 
data!\n");
+           bi = render::create_bitmap_info_empty();
+#endif
        }
-
-
-    /* sprite_instance */
-    void       increment_frame_and_check_for_loop()
-       // Increment m_current_frame, and take care of looping.
+    else
        {
-           m_current_frame++;
-
-           int frame_count = m_def->get_frame_count();
-           if (m_current_frame >= frame_count)
-               {
-                   // Loop.
-                   m_current_frame = 0;
-                   m_has_looped = true;
-                   if (frame_count > 1)
-                       {
-                           m_display_list.reset();
-                       }
-               }
+           bi = render::create_bitmap_info_empty();
        }
 
-    /* sprite_instance */
-    virtual void       advance(float delta_time)
-       {
-//         printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
+    assert(bi->get_ref_count() == 0);
 
-           // Keep this (particularly m_as_environment) alive during execution!
-           smart_ptr<as_object_interface>      this_ptr(this);
+    bitmap_character*  ch = new bitmap_character(bi);
 
-           assert(m_def != NULL && m_root != NULL);
+    m->add_bitmap_character(character_id, ch);
+}
 
-           // Advance everything in the display list.
-           m_display_list.advance(delta_time);
 
-           // mouse drag.
-           character::do_mouse_drag();
+#if TU_CONFIG_LINK_TO_ZLIB
+void   inflate_wrapper(tu_file* in, void* buffer, int buffer_bytes)
+    // Wrapper function -- uses Zlib to uncompress in_bytes worth
+    // of data from the input file into buffer_bytes worth of data
+    // into *buffer.
+{
+    assert(in);
+    assert(buffer);
+    assert(buffer_bytes > 0);
 
-           m_time_remainder += delta_time;
+    int err;
+    z_stream d_stream; /* decompression stream */
 
-           const float frame_time = 1.0f / m_root->get_frame_rate();   // @@ 
cache this
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
 
-           // Check for the end of frame
-           if (m_time_remainder >= frame_time)
-               {
-                   m_time_remainder -= frame_time;
+    d_stream.next_in  = 0;
+    d_stream.avail_in = 0;
 
-                   // Update current and next frames.
-                   if (m_play_state == PLAY)
-                       {
-                           int current_frame0 = m_current_frame;
-                           increment_frame_and_check_for_loop();
+    d_stream.next_out = (Byte*) buffer;
+    d_stream.avail_out = (uInt) buffer_bytes;
 
-                           // Execute the current frame's tags.
-                           if (m_current_frame != current_frame0)
-                               {
-                                   execute_frame_tags(m_current_frame);
-                               }
-                       }
+    err = inflateInit(&d_stream);
+    if (err != Z_OK) {
+       log_error("error: inflate_wrapper() inflateInit() returned %d\n", err);
+       return;
+    }
 
-                   // Dispatch onEnterFrame event.
-                   on_event(event_id::ENTER_FRAME);
+    Uint8      buf[1];
 
-                   do_actions();
+    for (;;) {
+       // Fill a one-byte (!) buffer.
+       buf[0] = in->read_byte();
+       d_stream.next_in = &buf[0];
+       d_stream.avail_in = 1;
 
-                   // Clean up display list (remove dead objects).
-                   m_display_list.update();
-               }
+       err = inflate(&d_stream, Z_SYNC_FLUSH);
+       if (err == Z_STREAM_END) break;
+       if (err != Z_OK)
+           {
+               log_error("error: inflate_wrapper() inflate() returned %d\n", 
err);
+           }
+    }
 
-           // Skip excess time.  TODO root caller should
-           // loop to prevent this happening; probably
-           // only root should keep m_time_remainder, and
-           // advance(dt) should be a discrete tick()
-           // with no dt.
-           m_time_remainder = fmod(m_time_remainder, frame_time);
-       }
-
-    /*sprite_instance*/
-    void       execute_frame_tags(int frame, bool state_only = false)
-       // Execute the tags associated with the specified frame.
-       // frame is 0-based
+    err = inflateEnd(&d_stream);
+    if (err != Z_OK)
        {
-           // Keep this (particularly m_as_environment) alive during execution!
-           smart_ptr<as_object_interface>      this_ptr(this);
+           log_error("error: inflate_wrapper() inflateEnd() return %d\n", err);
+       }
+}
+#endif // TU_CONFIG_LINK_TO_ZLIB
 
-           assert(frame >= 0);
-           assert(frame < m_def->get_frame_count());
 
-           // Execute this frame's init actions, if necessary.
-           if (m_init_actions_executed[frame] == false)
-               {
-                   const array<execute_tag*>*  init_actions = 
m_def->get_init_actions(frame);
-                   if (init_actions && init_actions->size() > 0)
-                       {
-                           // Need to execute these actions.
-                           for (int i= 0; i < init_actions->size(); i++)
-                               {
-                                   execute_tag*        e = (*init_actions)[i];
-                                   e->execute(this);
-                               }
+void   define_bits_jpeg3_loader(stream* in, int tag_type, 
movie_definition_sub* m)
+    // loads a define_bits_jpeg3 tag. This is a jpeg file with an alpha
+    // channel using zlib compression.
+{
+    assert(tag_type == 35);
 
-                           // Mark this frame done, so we never execute these 
init actions
-                           // again.
-                           m_init_actions_executed[frame] = true;
-                       }
-               }
+    Uint16     character_id = in->read_u16();
 
-           const array<execute_tag*>&  playlist = m_def->get_playlist(frame);
-           for (int i = 0; i < playlist.size(); i++)
-               {
-                   execute_tag*        e = playlist[i];
-                   if (state_only)
-                       {
-                           e->execute_state(this);
-                       }
-                   else
-                       {
-                           e->execute(this);
-                       }
-               }
-       }
+    IF_VERBOSE_PARSE(log_msg("  define_bits_jpeg3_loader: charid = %d pos = 
0x%x\n", character_id, in->get_position()));
 
+    Uint32     jpeg_size = in->read_u32();
+    Uint32     alpha_position = in->get_position() + jpeg_size;
+
+    bitmap_info*       bi = NULL;
 
-    /*sprite_instance*/
-    void       execute_frame_tags_reverse(int frame)
-       // Execute the tags associated with the specified frame, IN REVERSE.
-       // I.e. if it's an "add" tag, then we do a "remove" instead.
-       // Only relevant to the display-list manipulation tags: add, move, 
remove, replace.
-       //
-       // frame is 0-based
+    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
        {
-           // Keep this (particularly m_as_environment) alive during execution!
-           smart_ptr<as_object_interface>      this_ptr(this);
+#if TU_CONFIG_LINK_TO_JPEGLIB == 0 || TU_CONFIG_LINK_TO_ZLIB == 0
+           log_error("gnash is not linked to jpeglib/zlib -- can't load 
jpeg/zipped image data!\n");
+           bi = render::create_bitmap_info_empty();
+#else
+           //
+           // Read the image data.
+           //
+               
+           // Read rgb data.
+           image::rgba*        im = 
image::read_swf_jpeg3(in->get_underlying_stream());
 
-           assert(frame >= 0);
-           assert(frame < m_def->get_frame_count());
+           // Read alpha channel.
+           in->set_position(alpha_position);
 
-           const array<execute_tag*>&  playlist = m_def->get_playlist(frame);
-           for (int i = 0; i < playlist.size(); i++)
-               {
-                   execute_tag*        e = playlist[i];
-                   e->execute_state_reverse(this, frame);
-               }
-       }
+           int buffer_bytes = im->m_width * im->m_height;
+           Uint8*      buffer = new Uint8[buffer_bytes];
 
-               
-    /*sprite_instance*/
-    execute_tag*       find_previous_replace_or_add_tag(int frame, int depth, 
int id)
-       {
-           uint32      depth_id = ((depth & 0x0FFFF) << 16) | (id & 0x0FFFF);
+           inflate_wrapper(in->get_underlying_stream(), buffer, buffer_bytes);
 
-           for (int f = frame - 1; f >= 0; f--)
+           for (int i = 0; i < buffer_bytes; i++)
                {
-                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(f);
-                   for (int i = playlist.size() - 1; i >= 0; i--)
-                       {
-                           execute_tag*        e = playlist[i];
-                           if (e->get_depth_id_of_replace_or_add_tag() == 
depth_id)
-                               {
-                                   return e;
-                               }
-                       }
+                   im->m_data[4*i+3] = buffer[i];
                }
 
-           return NULL;
-       }
+           delete [] buffer;
 
+           bi = render::create_bitmap_info_rgba(im);
 
-    /*sprite_instance*/
-    void       execute_remove_tags(int frame)
-       // Execute any remove-object tags associated with the specified frame.
-       // frame is 0-based
-       {
-           assert(frame >= 0);
-           assert(frame < m_def->get_frame_count());
+           delete im;
+#endif
 
-           const array<execute_tag*>&  playlist = m_def->get_playlist(frame);
-           for (int i = 0; i < playlist.size(); i++)
-               {
-                   execute_tag*        e = playlist[i];
-                   if (e->is_remove_tag())
-                       {
-                           e->execute_state(this);
-                       }
-               }
        }
-
-
-    /*sprite_instance*/
-    void       do_actions()
-       // Take care of this frame's actions.
+    else
        {
-           // Keep m_as_environment alive during any method calls!
-           smart_ptr<as_object_interface>      this_ptr(this);
-
-           execute_actions(&m_as_environment, m_action_list);
-           m_action_list.resize(0);
+           bi = render::create_bitmap_info_empty();
        }
 
+    // Create bitmap character.
+    bitmap_character*  ch = new bitmap_character(bi);
 
-    /*sprite_instance*/
-    void       goto_frame(int target_frame_number)
-       // Set the sprite state at the specified frame number.
-       // 0-based frame numbers!!  (in contrast to ActionScript and Flash MX)
-       {
-//                     IF_VERBOSE_DEBUG(log_msg("sprite::goto_frame(%d)\n", 
target_frame_number));//xxxxx
-
-           target_frame_number = iclamp(target_frame_number, 0, 
m_def->get_frame_count() - 1);
-
-           if (target_frame_number < m_current_frame)
-               {
-                   for (int f = m_current_frame; f > target_frame_number; f--)
-                       {
-                           execute_frame_tags_reverse(f);
-                       }
-
-                   execute_frame_tags(target_frame_number, false);
-                   m_display_list.update();
-               }
-           else if (target_frame_number > m_current_frame)
-               {
-                   for (int f = m_current_frame + 1; f < target_frame_number; 
f++)
-                       {
-                           execute_frame_tags(f, true);
-                       }
-
-                   execute_frame_tags(target_frame_number, false);
-                   m_display_list.update();
-               }
-
-           m_current_frame = target_frame_number;      
-
-           // goto_frame stops by default.
-           m_play_state = STOP;
-       }
-
+    m->add_bitmap_character(character_id, ch);
+}
 
-    bool       goto_labeled_frame(const char* label)
-       // Look up the labeled frame, and jump to it.
-       {
-           int target_frame = -1;
-           if (m_def->get_labeled_frame(label, &target_frame))
-               {
-                   goto_frame(target_frame);
-                   return true;
-               }
-           else
-               {
-                   IF_VERBOSE_ACTION(
-                       log_error("error: movie_impl::goto_labeled_frame('%s') 
unknown label\n", label));
-                   return false;
-               }
-       }
 
-               
-    /*sprite_instance*/
-    void       display()
-       {
-           if (get_visible() == false)
-               {
-                   // We're invisible, so don't display!
-                   return;
-               }
+void   define_bits_lossless_2_loader(stream* in, int tag_type, 
movie_definition_sub* m)
+{
+    assert(tag_type == 20 || tag_type == 36);
 
-           m_display_list.display();
+    Uint16     character_id = in->read_u16();
+    Uint8      bitmap_format = in->read_u8();  // 3 == 8 bit, 4 == 16 bit, 5 
== 32 bit
+    Uint16     width = in->read_u16();
+    Uint16     height = in->read_u16();
 
-           do_display_callback();
-       }
+    IF_VERBOSE_PARSE(log_msg("  defbitslossless2: tag_type = %d, id = %d, fmt 
= %d, w = %d, h = %d\n",
+                            tag_type,
+                            character_id,
+                            bitmap_format,
+                            width,
+                            height));
 
-    /*sprite_instance*/
-    character* add_display_object(
-       Uint16 character_id,
-       const char* name,
-       const array<swf_event*>& event_handlers,
-       Uint16 depth,
-       bool replace_if_depth_is_occupied,
-       const cxform& color_transform,
-       const matrix& matrix,
-       float ratio,
-       Uint16 clip_depth)
-       // Add an object to the display list.
+    bitmap_info*       bi = NULL;
+    if (m->get_create_bitmaps() == DO_LOAD_BITMAPS)
        {
-           assert(m_def != NULL);
-
-           character_def*      cdef = m_def->get_character_def(character_id);
-           if (cdef == NULL)
-               {
-                   log_error("sprite::add_display_object(): unknown cid = 
%d\n", character_id);
-                   return NULL;
-               }
-
-           // If we already have this object on this
-           // plane, then move it instead of replacing
-           // it.
-           character*  existing_char = 
m_display_list.get_character_at_depth(depth);
-           if (existing_char
-               && existing_char->get_id() == character_id
-               && ((name == NULL && existing_char->get_name().length() == 0)
-                   || (name && existing_char->get_name() == name)))
+#if TU_CONFIG_LINK_TO_ZLIB == 0
+           log_error("gnash is not linked to zlib -- can't load zipped image 
data!\n");
+           return;
+#else
+           if (tag_type == 20)
                {
-//                             IF_VERBOSE_DEBUG(log_msg("add changed to move 
on depth %d\n", depth));//xxxxxx
-                   move_display_object(depth, true, color_transform, true, 
matrix, ratio, clip_depth);
-                   return NULL;
-               }
-           //printf("%s: character %s, id is %d, count is %d\n", __FUNCTION__, 
existing_char->get_name(), character_id,m_display_list.get_character_count()); 
// FIXME:
+                   // RGB image data.
+                   image::rgb* image = image::create_rgb(width, height);
 
-           assert(cdef);
-           smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-           assert(ch != NULL);
-           if (name != NULL && name[0] != 0)
-               {
-                   ch->set_name(name);
-               }
+                   if (bitmap_format == 3)
+                       {
+                           // 8-bit data, preceded by a palette.
 
-           // Attach event handlers (if any).
-           {for (int i = 0, n = event_handlers.size(); i < n; i++)
-               {
-                   event_handlers[i]->attach_to(ch.get_ptr());
-               }}
+                           const int   bytes_per_pixel = 1;
+                           int color_table_size = in->read_u8();
+                           color_table_size += 1;      // !! SWF stores one 
less than the actual size
 
-           m_display_list.add_display_object(
-               ch.get_ptr(),
-               depth,
-               replace_if_depth_is_occupied,
-               color_transform,
-               matrix,
-               ratio,
-               clip_depth);
-
-           assert(ch == NULL || ch->get_ref_count() > 1);
-           return ch.get_ptr();
-       }
+                           int pitch = (width * bytes_per_pixel + 3) & ~3;
 
+                           int buffer_bytes = color_table_size * 3 + pitch * 
height;
+                           Uint8*      buffer = new Uint8[buffer_bytes];
 
-    /*sprite_instance*/
-    void       move_display_object(
-       Uint16 depth,
-       bool use_cxform,
-       const cxform& color_xform,
-       bool use_matrix,
-       const matrix& mat,
-       float ratio,
-       Uint16 clip_depth)
-       // Updates the transform properties of the object at
-       // the specified depth.
-       {
-           m_display_list.move_display_object(depth, use_cxform, color_xform, 
use_matrix, mat, ratio, clip_depth);
-       }
+                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
 
+                           Uint8*      color_table = buffer;
 
-    /*sprite_instance*/
-    void       replace_display_object(
-       Uint16 character_id,
-       const char* name,
-       Uint16 depth,
-       bool use_cxform,
-       const cxform& color_transform,
-       bool use_matrix,
-       const matrix& mat,
-       float ratio,
-       Uint16 clip_depth)
-       {
-           assert(m_def != NULL);
-           // printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
character_id); // FIXME: debugging crap
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_in_row = buffer + 
color_table_size * 3 + j * pitch;
+                                   Uint8*      image_out_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint8       pixel = image_in_row[i 
* bytes_per_pixel];
+                                           image_out_row[i * 3 + 0] = 
color_table[pixel * 3 + 0];
+                                           image_out_row[i * 3 + 1] = 
color_table[pixel * 3 + 1];
+                                           image_out_row[i * 3 + 2] = 
color_table[pixel * 3 + 2];
+                                       }
+                               }
 
-           character_def*      cdef = m_def->get_character_def(character_id);
-           if (cdef == NULL)
-               {
-                   log_error("sprite::replace_display_object(): unknown cid = 
%d\n", character_id);
-                   return;
-               }
-           assert(cdef);
+                           delete [] buffer;
+                       }
+                   else if (bitmap_format == 4)
+                       {
+                           // 16 bits / pixel
+                           const int   bytes_per_pixel = 2;
+                           int pitch = (width * bytes_per_pixel + 3) & ~3;
 
-           smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-           assert(ch != NULL);
+                           int buffer_bytes = pitch * height;
+                           Uint8*      buffer = new Uint8[buffer_bytes];
 
-           if (name != NULL && name[0] != 0)
-               {
-                   ch->set_name(name);
-               }
+                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
+                       
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_in_row = buffer + j * 
pitch;
+                                   Uint8*      image_out_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint16      pixel = image_in_row[i 
* 2] | (image_in_row[i * 2 + 1] << 8);
+                                       
+                                           // @@ How is the data packed???  
I'm just guessing here that it's 565!
+                                           image_out_row[i * 3 + 0] = (pixel 
>> 8) & 0xF8;     // red
+                                           image_out_row[i * 3 + 1] = (pixel 
>> 3) & 0xFC;     // green
+                                           image_out_row[i * 3 + 2] = (pixel 
<< 3) & 0xF8;     // blue
+                                       }
+                               }
+                       
+                           delete [] buffer;
+                       }
+                   else if (bitmap_format == 5)
+                       {
+                           // 32 bits / pixel, input is ARGB format (???)
+                           const int   bytes_per_pixel = 4;
+                           int pitch = width * bytes_per_pixel;
 
-           m_display_list.replace_display_object(
-               ch.get_ptr(),
-               depth,
-               use_cxform,
-               color_transform,
-               use_matrix,
-               mat,
-               ratio,
-               clip_depth);
-       }
+                           int buffer_bytes = pitch * height;
+                           Uint8*      buffer = new Uint8[buffer_bytes];
 
+                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
+                       
+                           // Need to re-arrange ARGB into RGB.
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_in_row = buffer + j * 
pitch;
+                                   Uint8*      image_out_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint8       a = image_in_row[i * 4 
+ 0];
+                                           Uint8       r = image_in_row[i * 4 
+ 1];
+                                           Uint8       g = image_in_row[i * 4 
+ 2];
+                                           Uint8       b = image_in_row[i * 4 
+ 3];
+                                           image_out_row[i * 3 + 0] = r;
+                                           image_out_row[i * 3 + 1] = g;
+                                           image_out_row[i * 3 + 2] = b;
+                                           a = a;      // Inhibit warning.
+                                       }
+                               }
 
-    /*sprite_instance*/
-    void       replace_display_object(
-       character* ch,
-       const char* name,
-       Uint16 depth,
-       bool use_cxform,
-       const cxform& color_transform,
-       bool use_matrix,
-       const matrix& mat,
-       float ratio,
-       Uint16 clip_depth)
-       {
-           printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
ch->get_id()); // FIXME:
+                           delete [] buffer;
+                       }
 
-           assert(ch != NULL);
+//                             bitmap_character*       ch = new 
bitmap_character(image);
+                   bi = render::create_bitmap_info_rgb(image);
+                   delete image;
 
-           if (name != NULL && name[0] != 0)
-               {
-                   ch->set_name(name);
+//                             // add image to movie, under character id.
+//                             m->add_bitmap_character(character_id, ch);
                }
+           else
+               {
+                   // RGBA image data.
+                   assert(tag_type == 36);
 
-           m_display_list.replace_display_object(
-               ch,
-               depth,
-               use_cxform,
-               color_transform,
-               use_matrix,
-               mat,
-               ratio,
-               clip_depth);
-       }
+                   image::rgba*        image = image::create_rgba(width, 
height);
 
+                   if (bitmap_format == 3)
+                       {
+                           // 8-bit data, preceded by a palette.
 
-    /*sprite_instance*/
-    void       remove_display_object(Uint16 depth, int id)
-       // Remove the object at the specified depth.
-       // If id != -1, then only remove the object at depth with matching id.
-       {
-           m_display_list.remove_display_object(depth, id);
-       }
+                           const int   bytes_per_pixel = 1;
+                           int color_table_size = in->read_u8();
+                           color_table_size += 1;      // !! SWF stores one 
less than the actual size
 
+                           int pitch = (width * bytes_per_pixel + 3) & ~3;
 
-    /*sprite_instance*/
-    void       add_action_buffer(action_buffer* a)
-       // Add the given action buffer to the list of action
-       // buffers to be processed at the end of the next
-       // frame advance.
-       {
-           m_action_list.push_back(a);
-       }
+                           int buffer_bytes = color_table_size * 4 + pitch * 
height;
+                           Uint8*      buffer = new Uint8[buffer_bytes];
 
+                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
 
-    /*sprite_instance*/
-    int        get_id_at_depth(int depth)
-       // For debugging -- return the id of the character at the specified 
depth.
-       // Return -1 if nobody's home.
-       {
-           int index = m_display_list.get_display_index(depth);
-           if (index == -1)
-               {
-                   return -1;
-               }
+                           Uint8*      color_table = buffer;
 
-           character*  ch = 
m_display_list.get_display_object(index).m_character.get_ptr();
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_in_row = buffer + 
color_table_size * 4 + j * pitch;
+                                   Uint8*      image_out_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint8       pixel = image_in_row[i 
* bytes_per_pixel];
+                                           image_out_row[i * 4 + 0] = 
color_table[pixel * 4 + 0];
+                                           image_out_row[i * 4 + 1] = 
color_table[pixel * 4 + 1];
+                                           image_out_row[i * 4 + 2] = 
color_table[pixel * 4 + 2];
+                                           image_out_row[i * 4 + 3] = 
color_table[pixel * 4 + 3];
+                                       }
+                               }
 
-           return ch->get_id();
-       }
+                           delete [] buffer;
+                       }
+                   else if (bitmap_format == 4)
+                       {
+                           // 16 bits / pixel
+                           const int   bytes_per_pixel = 2;
+                           int pitch = (width * bytes_per_pixel + 3) & ~3;
 
+                           int buffer_bytes = pitch * height;
+                           Uint8*      buffer = new Uint8[buffer_bytes];
 
-    //
-    // ActionScript support
-    //
+                           inflate_wrapper(in->get_underlying_stream(), 
buffer, buffer_bytes);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
+                       
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_in_row = buffer + j * 
pitch;
+                                   Uint8*      image_out_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint16      pixel = image_in_row[i 
* 2] | (image_in_row[i * 2 + 1] << 8);
+                                       
+                                           // @@ How is the data packed???  
I'm just guessing here that it's 565!
+                                           image_out_row[i * 4 + 0] = 255;     
                // alpha
+                                           image_out_row[i * 4 + 1] = (pixel 
>> 8) & 0xF8;     // red
+                                           image_out_row[i * 4 + 2] = (pixel 
>> 3) & 0xFC;     // green
+                                           image_out_row[i * 4 + 3] = (pixel 
<< 3) & 0xF8;     // blue
+                                       }
+                               }
+                       
+                           delete [] buffer;
+                       }
+                   else if (bitmap_format == 5)
+                       {
+                           // 32 bits / pixel, input is ARGB format
 
+                           inflate_wrapper(in->get_underlying_stream(), 
image->m_data, width * height * 4);
+                           assert(in->get_position() <= 
in->get_tag_end_position());
+                       
+                           // Need to re-arrange ARGB into RGBA.
+                           for (int j = 0; j < height; j++)
+                               {
+                                   Uint8*      image_row = 
image::scanline(image, j);
+                                   for (int i = 0; i < width; i++)
+                                       {
+                                           Uint8       a = image_row[i * 4 + 
0];
+                                           Uint8       r = image_row[i * 4 + 
1];
+                                           Uint8       g = image_row[i * 4 + 
2];
+                                           Uint8       b = image_row[i * 4 + 
3];
+                                           image_row[i * 4 + 0] = r;
+                                           image_row[i * 4 + 1] = g;
+                                           image_row[i * 4 + 2] = b;
+                                           image_row[i * 4 + 3] = a;
+                                       }
+                               }
+                       }
 
-    /* sprite_instance */
-    virtual void       set_variable(const char* path_to_var, const char* 
new_value)
-       {
-           assert(m_parent == NULL);   // should only be called on the root 
movie.
+                   bi = render::create_bitmap_info_rgba(image);
+//                             bitmap_character*       ch = new 
bitmap_character(image);
+                   delete image;
 
-           if (path_to_var == NULL)
-               {
-                   log_error("error: NULL path_to_var passed to 
set_variable()\n");
-                   return;
-               }
-           if (new_value == NULL)
-               {
-                   log_error("error: NULL passed to set_variable('%s', 
NULL)\n", path_to_var);
-                   return;
+//                             // add image to movie, under character id.
+//                             m->add_bitmap_character(character_id, ch);
                }
-
-           array<with_stack_entry>     empty_with_stack;
-           tu_string   path(path_to_var);
-           as_value    val(new_value);
-
-           m_as_environment.set_variable(path, val, empty_with_stack);
+#endif // TU_CONFIG_LINK_TO_ZLIB
        }
-
-    /* sprite_instance */
-    virtual void       set_variable(const char* path_to_var, const wchar_t* 
new_value)
+    else
        {
-           if (path_to_var == NULL)
-               {
-                   log_error("error: NULL path_to_var passed to 
set_variable()\n");
-                   return;
-               }
-           if (new_value == NULL)
-               {
-                   log_error("error: NULL passed to set_variable('%s', 
NULL)\n", path_to_var);
-                   return;
-               }
-
-           assert(m_parent == NULL);   // should only be called on the root 
movie.
-
-           array<with_stack_entry>     empty_with_stack;
-           tu_string   path(path_to_var);
-           as_value    val(new_value);
-
-           m_as_environment.set_variable(path, val, empty_with_stack);
+           bi = render::create_bitmap_info_empty();
        }
+    assert(bi->get_ref_count() == 0);
 
-    /* sprite_instance */
-    virtual const char*        get_variable(const char* path_to_var) const
-       {
-           assert(m_parent == NULL);   // should only be called on the root 
movie.
-
-           array<with_stack_entry>     empty_with_stack;
-           tu_string   path(path_to_var);
+    bitmap_character*  ch = new bitmap_character(bi);
 
-           // NOTE: this is static so that the string
-           // value won't go away after we return!!!
-           // It'll go away during the next call to this
-           // function though!!!  NOT THREAD SAFE!
-           static as_value     val;
+    // add image to movie, under character id.
+    m->add_bitmap_character(character_id, ch);
+}
 
-           val = m_as_environment.get_variable(path, empty_with_stack);
 
-           return val.to_string();     // ack!
-       }
+void   define_shape_loader(stream* in, int tag_type, movie_definition_sub* m)
+{
+    assert(tag_type == 2
+          || tag_type == 22
+          || tag_type == 32);
 
-               
-    /* sprite_instance */
-    virtual void       set_member(const tu_stringi& name, const as_value& val)
-       // Set the named member to the value.  Return true if we have
-       // that member; false otherwise.
-       {
-           as_standard_member  std_member = get_standard_member(name);
-           switch (std_member)
-               {
-               default:
-               case M_INVALID_MEMBER:
-                   break;
-               case M_X:
-                   //if (name == "_x")
-               {
-                   matrix      m = get_matrix();
-                   m.m_[0][2] = (float) PIXELS_TO_TWIPS(val.to_number());
-                   set_matrix(m);
+    Uint16     character_id = in->read_u16();
+    IF_VERBOSE_PARSE(log_msg("  shape_loader: id = %d\n", character_id));
 
-                   m_accept_anim_moves = false;
+    shape_character_def*       ch = new shape_character_def;
+    ch->read(in, tag_type, true, m);
 
-                   return;
-               }
-               case M_Y:
-                   //else if (name == "_y")
-               {
-                   matrix      m = get_matrix();
-                   m.m_[1][2] = (float) PIXELS_TO_TWIPS(val.to_number());
-                   set_matrix(m);
+    IF_VERBOSE_PARSE(log_msg("  bound rect:"); ch->get_bound().print());
 
-                   m_accept_anim_moves = false;
+    m->add_character(character_id, ch);
+}
 
-                   return;
-               }
-               case M_XSCALE:
-                   //else if (name == "_xscale")
-               {
-                   matrix      m = get_matrix();
+void define_shape_morph_loader(stream* in, int tag_type, movie_definition_sub* 
m)
+{
+    assert(tag_type == 46);
+    Uint16 character_id = in->read_u16();
+    IF_VERBOSE_PARSE(log_msg("  shape_morph_loader: id = %d\n", character_id));
+    morph2_character_def* morph = new morph2_character_def;
+    morph->read(in, tag_type, true, m);
+    m->add_character(character_id, morph);
+}
 
-                   // Decompose matrix and insert the desired value.
-                   float       x_scale = (float) val.to_number() / 100.f;      
// input is in percent
-                   float       y_scale = m.get_y_scale();
-                   float       rotation = m.get_rotation();
-                   m.set_scale_rotation(x_scale, y_scale, rotation);
+//
+// font loaders
+//
 
-                   set_matrix(m);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_YSCALE:
-                   //else if (name == "_yscale")
-               {
-                   matrix      m = get_matrix();
 
-                   // Decompose matrix and insert the desired value.
-                   float       x_scale = m.get_x_scale();
-                   float       y_scale = (float) val.to_number() / 100.f;      
// input is in percent
-                   float       rotation = m.get_rotation();
-                   m.set_scale_rotation(x_scale, y_scale, rotation);
+void   define_font_loader(stream* in, int tag_type, movie_definition_sub* m)
+    // Load a DefineFont or DefineFont2 tag.
+{
+    assert(tag_type == 10 || tag_type == 48);
 
-                   set_matrix(m);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_ALPHA:
-                   //else if (name == "_alpha")
-               {
-                   // Set alpha modulate, in percent.
-                   cxform      cx = get_cxform();
-                   cx.m_[3][0] = float(val.to_number()) / 100.f;
-                   set_cxform(cx);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_VISIBLE:
-                   //else if (name == "_visible")
-               {
-                   set_visible(val.to_bool());
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_WIDTH:
-                   //else if (name == "_width")
-               {
-                   // @@ tulrich: is parameter in world-coords or local-coords?
-                   matrix      m = get_matrix();
-                   m.m_[0][0] = float(PIXELS_TO_TWIPS(val.to_number()));
-                   float w = get_width();
-                   if (fabsf(w) > 1e-6f)
-                       {
-                           m.m_[0][0] /= w;
-                       }
-                   set_matrix(m);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_HEIGHT:
-                   //else if (name == "_height")
-               {
-                   // @@ tulrich: is parameter in world-coords or local-coords?
-                   matrix      m = get_matrix();
-                   m.m_[1][1] = float(PIXELS_TO_TWIPS(val.to_number()));
-                   float h = get_width();
-                   if (fabsf(h) > 1e-6f)
-                       {
-                           m.m_[1][1] /= h;
-                       }
-                   set_matrix(m);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_ROTATION:
-                   //else if (name == "_rotation")
-               {
-                   matrix      m = get_matrix();
+    Uint16     font_id = in->read_u16();
+               
+    font*      f = new font;
+    f->read(in, tag_type, m);
 
-                   // Decompose matrix and insert the desired value.
-                   float       x_scale = m.get_x_scale();
-                   float       y_scale = m.get_y_scale();
-                   float       rotation = (float) val.to_number() * 
float(M_PI) / 180.f;       // input is in degrees
-                   m.set_scale_rotation(x_scale, y_scale, rotation);
+    m->add_font(font_id, f);
 
-                   set_matrix(m);
-                   m_accept_anim_moves = false;
-                   return;
-               }
-               case M_HIGHQUALITY:
-                   //else if (name == "_highquality")
-               {
-                   // @@ global { 0, 1, 2 }
-//                             // Whether we're in high quality mode or not.
-//                             val->set(true);
-                   return;
-               }
-               case M_FOCUSRECT:
-                   //else if (name == "_focusrect")
-               {
-//                             // Is a yellow rectangle visible around a 
focused movie clip (?)
-//                             val->set(false);
-                   return;
-               }
-               case M_SOUNDBUFTIME:
-                   //else if (name == "_soundbuftime")
-               {
-                   // @@ global
-//                             // Number of seconds before sound starts to 
stream.
-//                             val->set(0.0);
-                   return;
-               }
-               }       // end switch
+    // Automatically keeping fonts in fontlib is
+    // problematic.  The app should be responsible for
+    // optionally adding fonts to fontlib.
+    // //fontlib::add_font(f);
+}
 
-                       // Not a built-in property.  See if we have a
-                       // matching edit_text character in our display
-                       // list.
-           bool        text_val = val.get_type() == as_value::STRING
-               || val.get_type() == as_value::NUMBER;
-           if (text_val)
-               {
-                   bool        success = false;
-                   for (int i = 0, n = m_display_list.get_character_count(); i 
< n; i++)
-                       {
-                           character*  ch = m_display_list.get_character(i);
-                           // CASE INSENSITIVE compare.  In ActionScript 2.0, 
this
-                           // changes to CASE SENSITIVE!!!
-                           if (name == ch->get_text_name())
-                               {
-                                   const char* text = val.to_string();
-                                   ch->set_text_value(text);
-                                   success = true;
-                               }
-                       }
-                   if (success) return;
-               }
 
-           // If that didn't work, set a variable within this environment.
-           m_as_environment.set_member(name, val);
+void   define_font_info_loader(stream* in, int tag_type, movie_definition_sub* 
m)
+    // Load a DefineFontInfo tag.  This adds information to an
+    // existing font.
+{
+    assert(tag_type == 13);
+
+    Uint16     font_id = in->read_u16();
+               
+    font*      f = m->get_font(font_id);
+    if (f)
+       {
+           f->read_font_info(in);
+       }
+    else
+       {
+           log_error("define_font_info_loader: can't find font w/ id %d\n", 
font_id);
        }
+}
 
+void swf_event::read(stream* in, Uint32 flags)
+{
+    assert(flags != 0);
 
-    /* sprite_instance */
-    virtual bool       get_member(const tu_stringi& name, as_value* val)
-       // Set *val to the value of the named member and
-       // return true, if we have the named member.
-       // Otherwise leave *val alone and return false.
+    // Scream if more than one bit is set, since we're not set up to handle
+    // that, and it doesn't seem possible to express in ActionScript source,
+    // so it's important to know if this ever occurs in the wild.
+    if (flags & (flags - 1))
        {
-           as_standard_member  std_member = get_standard_member(name);
-           switch (std_member)
-               {
-               default:
-               case M_INVALID_MEMBER:
-                   break;
-               case M_X:
-                   //if (name == "_x")
-               {
-                   matrix      m = get_matrix();
-                   val->set_double(TWIPS_TO_PIXELS(m.m_[0][2]));
-                   return true;
-               }
-               case M_Y:
-                   //else if (name == "_y")
-               {
-                   matrix      m = get_matrix();
-                   val->set_double(TWIPS_TO_PIXELS(m.m_[1][2]));
-                   return true;
-               }
-               case M_XSCALE:
-                   //else if (name == "_xscale")
-               {
-                   matrix m = get_matrix();    // @@ or get_world_matrix()?  
Test this.
-                   float xscale = m.get_x_scale();
-                   val->set_double(xscale * 100);              // result in 
percent
-                   return true;
-               }
-               case M_YSCALE:
-                   //else if (name == "_yscale")
-               {
-                   matrix m = get_matrix();    // @@ or get_world_matrix()?  
Test this.
-                   float yscale = m.get_y_scale();
-                   val->set_double(yscale * 100);              // result in 
percent
-                   return true;
-               }
-               case M_CURRENTFRAME:
-                   //else if (name == "_currentframe")
-               {
-                   val->set_int(m_current_frame + 1);
-                   return true;
-               }
-               case M_TOTALFRAMES:
-                   //else if (name == "_totalframes")
-               {
-                   // number of frames.  Read only.
-                   val->set_int(m_def->get_frame_count());
-                   return true;
-               }
-               case M_ALPHA:
-                   //else if (name == "_alpha")
-               {
-                   // Alpha units are in percent.
-                   val->set_double(get_cxform().m_[3][0] * 100.f);
-                   return true;
-               }
-               case M_VISIBLE:
-                   //else if (name == "_visible")
-               {
-                   val->set_bool(get_visible());
-                   return true;
-               }
-               case M_WIDTH:
-                   //else if (name == "_width")
-               {
-                   matrix      m = get_world_matrix();
-                   rect        transformed_rect;
+           log_error("error: swf_event::read() -- more than one event type 
encoded!  "
+                     "unexpected! flags = 0x%x\n", flags);
+       }
 
-                   // @@ not sure about this...
-                   rect        source_rect;
-                   source_rect.m_x_min = 0;
-                   source_rect.m_y_min = 0;
-                   source_rect.m_x_max = (float) get_width();
-                   source_rect.m_y_max = (float) get_height();
-
-                   
transformed_rect.enclose_transformed_rect(get_world_matrix(), source_rect);
-                   val->set_double(TWIPS_TO_PIXELS(transformed_rect.width()));
-                   return true;
-               }
-               case M_HEIGHT:
-                   //else if (name == "_height")
-               {
-                   rect        transformed_rect;
+    // 14 bits reserved, 18 bits used
 
-                   // @@ not sure about this...
-                   rect        source_rect;
-                   source_rect.m_x_min = 0;
-                   source_rect.m_y_min = 0;
-                   source_rect.m_x_max = (float) get_width();
-                   source_rect.m_y_max = (float) get_height();
-
-                   
transformed_rect.enclose_transformed_rect(get_world_matrix(), source_rect);
-                   val->set_double(TWIPS_TO_PIXELS(transformed_rect.height()));
-                   return true;
-               }
-               case M_ROTATION:
-                   //else if (name == "_rotation")
-               {
-                   // Verified against Macromedia player using 
samples/test_rotation.swf
-                   float       angle = get_matrix().get_rotation();
+    static const event_id      s_code_bits[18] =
+       {
+           event_id::LOAD,
+           event_id::ENTER_FRAME,
+           event_id::UNLOAD,
+           event_id::MOUSE_MOVE,
+           event_id::MOUSE_DOWN,
+           event_id::MOUSE_UP,
+           event_id::KEY_DOWN,
+           event_id::KEY_UP,
+           event_id::DATA,
+           event_id::INITIALIZE,
+           event_id::PRESS,
+           event_id::RELEASE,
+           event_id::RELEASE_OUTSIDE,
+           event_id::ROLL_OVER,
+           event_id::ROLL_OUT,
+           event_id::DRAG_OVER,
+           event_id::DRAG_OUT,
+       };
 
-                   // Result is CLOCKWISE DEGREES, [-180,180]
-                   angle *= 180.0f / float(M_PI);
+    // Let's see if the event flag we received is for an event that we know of
+    if ((pow(2,int(sizeof(s_code_bits)/sizeof(s_code_bits[0])))-1) < flags)
+       {
+           log_error("error: swf_event::read() -- unknown / unhandled event 
type received, flags = 0x%x\n", flags);
+       }
 
-                   val->set_double(angle);
-                   return true;
-               }
-               case M_TARGET:
-                   //else if (name == "_target")
-               {
-                   // Full path to this object; e.g. 
"/_level0/sprite1/sprite2/ourSprite"
-                   val->set_string("/_root");
-                   return true;
-               }
-               case M_FRAMESLOADED:
-                   //else if (name == "_framesloaded")
-               {
-                   val->set_int(m_def->get_frame_count());
-                   return true;
-               }
-               case M_NAME:
-                   //else if (name == "_name")
-               {
-                   val->set_tu_string(get_name());
-                   return true;
-               }
-               case M_DROPTARGET:
-                   //else if (name == "_droptarget")
-               {
-                   // Absolute path in slash syntax where we were last dropped 
(?)
-                   // @@ TODO
-                   val->set_string("/_root");
-                   return true;
-               }
-               case M_URL:
-                   //else if (name == "_url")
-               {
-                   // our URL.
-                   val->set_string("gnash");
-                   return true;
-               }
-               case M_HIGHQUALITY:
-                   //else if (name == "_highquality")
-               {
-                   // Whether we're in high quality mode or not.
-                   val->set_bool(true);
-                   return true;
-               }
-               case M_FOCUSRECT:
-                   //else if (name == "_focusrect")
-               {
-                   // Is a yellow rectangle visible around a focused movie 
clip (?)
-                   val->set_bool(false);
-                   return true;
-               }
-               case M_SOUNDBUFTIME:
-                   //else if (name == "_soundbuftime")
+    for (int i = 0, mask = 1; i < 
int(sizeof(s_code_bits)/sizeof(s_code_bits[0])); i++, mask <<= 1)
+       {
+           if (flags & mask)
                {
-                   // Number of seconds before sound starts to stream.
-                   val->set_double(0.0);
-                   return true;
+                   m_event = s_code_bits[i];
+                   break;
                }
-               case M_XMOUSE:
-                   //else if (name == "_xmouse")
-               {
-                   // Local coord of mouse IN PIXELS.
-                   int x, y, buttons;
-                   assert(m_root);
-                   m_root->get_mouse_state(&x, &y, &buttons);
+       }
 
-                   matrix      m = get_world_matrix();
+    // what to do w/ key_press???  Is the data in the reserved parts of the 
flags???
+    if (flags & (1 << 17))
+       {
+           log_error("swf_event::read -- KEY_PRESS found, not handled yet, 
flags = 0x%x\n", flags);
+       }
 
-                   point       a(PIXELS_TO_TWIPS(x), PIXELS_TO_TWIPS(y));
-                   point       b;
-                               
-                   m.transform_by_inverse(&b, a);
+    Uint32     event_length = in->read_u32();
+    UNUSED(event_length);
 
-                   val->set_double(TWIPS_TO_PIXELS(b.m_x));
-                   return true;
-               }
-               case M_YMOUSE:
-                   //else if (name == "_ymouse")
-               {
-                   // Local coord of mouse IN PIXELS.
-                   int x, y, buttons;
-                   assert(m_root);
-                   m_root->get_mouse_state(&x, &y, &buttons);
+    // Read the actions.
+    IF_VERBOSE_ACTION(log_msg("---- actions for event %s\n", 
m_event.get_function_name().c_str()));
+    m_action_buffer.read(in);
 
-                   matrix      m = get_world_matrix();
+    if (m_action_buffer.get_length() != (int) event_length)
+       {
+           log_error("error -- swf_event::read(), event_length = %d, but read 
%d\n",
+                     event_length,
+                     m_action_buffer.get_length());
+           // @@ discard this event handler??
+       }
 
-                   point       a(PIXELS_TO_TWIPS(x), PIXELS_TO_TWIPS(y));
-                   point       b;
-                               
-                   m.transform_by_inverse(&b, a);
+    // Create a function to execute the actions.
+    array<with_stack_entry>    empty_with_stack;
+    as_as_function*    func = new as_as_function(&m_action_buffer, NULL, 0, 
empty_with_stack);
+    func->set_length(m_action_buffer.get_length());
 
-                   val->set_double(TWIPS_TO_PIXELS(b.m_y));
-                   return true;
-               }
-               case M_PARENT:
-               {
-                   
val->set_as_object_interface(static_cast<as_object_interface*>(m_parent));
-                   return true;
-               }
-               case M_ONLOAD:
-               {
-                   if (m_as_environment.get_member(name, val))
-                       {
-                           return true;
-                       }
-                   // Optimization: if no hit, don't bother looking in the 
display list, etc.
-                   return false;
-               }
-               }       // end switch
+    m_method.set_as_as_function(func);
+}
 
-                       // Try variables.
-           if (m_as_environment.get_member(name, val))
-               {
-                   return true;
-               }
 
-           // Not a built-in property.  Check items on our
-           // display list.
-           character*  ch = m_display_list.get_character_by_name_i(name);
-           if (ch)
-               {
-                   // Found object.
-                   
val->set_as_object_interface(static_cast<as_object_interface*>(ch));
-                   return true;
-               }
 
-           // Try static builtin functions.
-           assert(s_sprite_builtins);
-           if (s_sprite_builtins->get_member(name, val))
-               {
-                   return true;
-               }
+//
+// place_object_2
+//
+       
+struct place_object_2 : public execute_tag
+{
+    int        m_tag_type;
+    char*      m_name;
+    float      m_ratio;
+    cxform     m_color_transform;
+    matrix     m_matrix;
+    bool       m_has_matrix;
+    bool       m_has_cxform;
+    Uint16     m_depth;
+    Uint16     m_character_id;
+    Uint16     m_clip_depth;
+    enum place_type {
+       PLACE,
+       MOVE,
+       REPLACE,
+    } m_place_type;
+    array<swf_event*>  m_event_handlers;
 
-           return false;
-       }
 
+    place_object_2()
+       :
+       m_tag_type(0),
+       m_name(NULL),
+       m_ratio(0),
+       m_has_matrix(false),
+       m_has_cxform(false),
+       m_depth(0),
+       m_character_id(0),
+       m_clip_depth(0),
+       m_place_type(PLACE)
+       {
+       }
 
-    /* sprite_instance */
-    virtual movie*     get_relative_target(const tu_string& name)
-       // Find the movie which is one degree removed from us,
-       // given the relative pathname.
-       //
-       // If the pathname is "..", then return our parent.
-       // If the pathname is ".", then return ourself.  If
-       // the pathname is "_level0" or "_root", then return
-       // the root movie.
-       //
-       // Otherwise, the name should refer to one our our
-       // named characters, so we return it.
-       //
-       // NOTE: In ActionScript 2.0, top level names (like
-       // "_root" and "_level0") are CASE SENSITIVE.
-       // Character names in a display list are CASE
-       // SENSITIVE. Member names are CASE INSENSITIVE.  Gah.
-       //
-       // In ActionScript 1.0, everything seems to be CASE
-       // INSENSITIVE.
+    ~place_object_2()
        {
-           if (name == "." || name == "this")
-               {
-                   return this;
-               }
-           else if (name == "..")
-               {
-                   return get_parent();
-               }
-           else if (name == "_level0"
-                    || name == "_root")
+           delete [] m_name;
+           m_name = NULL;
+
+           for (int i = 0, n = m_event_handlers.size(); i < n; i++)
                {
-                   return m_root->m_movie.get_ptr();
+                   delete m_event_handlers[i];
                }
-
-           // See if we have a match on the display list.
-           return m_display_list.get_character_by_name(name);
+           m_event_handlers.resize(0);
        }
 
-
-    /* sprite_instance */
-    virtual void       call_frame_actions(const as_value& frame_spec)
-       // Execute the actions for the specified frame.  The
-       // frame_spec could be an integer or a string.
+    void       read(stream* in, int tag_type, int movie_version)
        {
-           int frame_number = -1;
+           assert(tag_type == 4 || tag_type == 26);
 
-           // Figure out what frame to call.
-           if (frame_spec.get_type() == as_value::STRING)
-               {
-                   if (m_def->get_labeled_frame(frame_spec.to_string(), 
&frame_number) == false)
-                       {
-                           // Try converting to integer.
-                           frame_number = (int) frame_spec.to_number();
-                       }
-               }
-           else
-               {
-                   // convert from 1-based to 0-based
-                   frame_number = (int) frame_spec.to_number() - 1;
-               }
+           m_tag_type = tag_type;
 
-           if (frame_number < 0 || frame_number >= m_def->get_frame_count())
+           if (tag_type == 4)
                {
-                   // No dice.
-                   log_error("error: call_frame('%s') -- unknown frame\n", 
frame_spec.to_string());
-                   return;
-               }
+                   // Original place_object tag; very simple.
+                   m_character_id = in->read_u16();
+                   m_depth = in->read_u16();
+                   m_matrix.read(in);
 
-           int top_action = m_action_list.size();
+                   IF_VERBOSE_PARSE(
+                       log_msg("  char_id = %d\n"
+                               "  depth = %d\n"
+                               "  mat = \n",
+                               m_character_id,
+                               m_depth);
+                       m_matrix.print());
 
-           // Execute the actions.
-           const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame_number);
-           for (int i = 0; i < playlist.size(); i++)
-               {
-                   execute_tag*        e = playlist[i];
-                   if (e->is_action_tag())
+                   if (in->get_position() < in->get_tag_end_position())
                        {
-                           e->execute(this);
+                           m_color_transform.read_rgb(in);
+                           IF_VERBOSE_PARSE(log_msg("  cxform:\n"); 
m_color_transform.print());
                        }
                }
-
-           // Execute any new actions triggered by the tag,
-           // leaving existing actions to be executed.
-           while (m_action_list.size() > top_action)
+           else if (tag_type == 26)
                {
-                   m_action_list[top_action]->execute(&m_as_environment);
-                   m_action_list.remove(top_action);
-               }
-           assert(m_action_list.size() == top_action);
-       }
+                   in->align();
 
+                   bool        has_actions = in->read_uint(1) ? true : false;
+                   bool        has_clip_bracket = in->read_uint(1) ? true : 
false;
+                   bool        has_name = in->read_uint(1) ? true : false;
+                   bool        has_ratio = in->read_uint(1) ? true : false;
+                   bool        has_cxform = in->read_uint(1) ? true : false;
+                   bool        has_matrix = in->read_uint(1) ? true : false;
+                   bool        has_char = in->read_uint(1) ? true : false;
+                   bool        flag_move = in->read_uint(1) ? true : false;
 
-    /* sprite_instance */
-    virtual void       set_drag_state(const drag_state& st)
-       {
-           m_root->m_drag_state = st;
-       }
+                   m_depth = in->read_u16();
+                   IF_VERBOSE_PARSE(log_msg("  depth = %d\n", m_depth));
 
-    /* sprite_instance */
-    virtual void       stop_drag()
-       {
-           assert(m_parent == NULL);   // we must be the root movie!!!
-                       
-           m_root->stop_drag();
-       }
+                   if (has_char) {
+                       m_character_id = in->read_u16();
+                       IF_VERBOSE_PARSE(log_msg("  char id = %d\n", 
m_character_id));
+                   }
+
+                   if (has_matrix) {
+                       m_has_matrix = true;
+                       m_matrix.read(in);
+                       IF_VERBOSE_PARSE(log_msg("  mat:\n"); m_matrix.print());
+                   }
+                   if (has_cxform) {
+                       m_has_cxform = true;
+                       m_color_transform.read_rgba(in);
+                       IF_VERBOSE_PARSE(log_msg("  cxform:\n"); 
m_color_transform.print());
+                   }
+                               
+                   if (has_ratio) {
+                       m_ratio = (float)in->read_u16() / (float)65535;
+                       IF_VERBOSE_PARSE(log_msg("  ratio: %f\n", m_ratio));
+                   }
+                               
+                   if (has_name) {
+                       m_name = in->read_string();
+                       IF_VERBOSE_PARSE(log_msg("  name = %s\n", m_name ? 
m_name : "<null>"));
+                   }
+                   if (has_clip_bracket) {
+                       m_clip_depth = in->read_u16(); 
+                       IF_VERBOSE_PARSE(log_msg("  clip_depth = %d\n", 
m_clip_depth));
+                   }
+                   if (has_actions)
+                       {
+                           Uint16      reserved = in->read_u16();
+                           UNUSED(reserved);
+
+                           // The logical 'or' of all the following handlers.
+                           // I don't think we care about this...
+                           Uint32      all_flags = 0;
+                           if (movie_version >= 6)
+                               {
+                                   all_flags = in->read_u32();
+                               }
+                           else
+                               {
+                                   all_flags = in->read_u16();
+                               }
+                           UNUSED(all_flags);
+
+                           IF_VERBOSE_PARSE(log_msg("  actions: flags = 
0x%X\n", all_flags));
 
+                           // Read swf_events.
+                           for (;;)
+                               {
+                                   // Read event.
+                                   in->align();
 
-    /* sprite_instance */
-    virtual void       get_drag_state(drag_state* st)
-       {
-           *st = m_root->m_drag_state;
-       }
+                                   Uint32      this_flags = 0;
+                                   if (movie_version >= 6)
+                                       {
+                                           this_flags = in->read_u32();
+                                       }
+                                   else
+                                       {
+                                           this_flags = in->read_u16();
+                                       }
 
+                                   if (this_flags == 0)
+                                       {
+                                           // Done with events.
+                                           break;
+                                       }
 
-    void       clone_display_object(const tu_string& name, const tu_string& 
newname, Uint16 depth)
-       // Duplicate the object with the specified name and add it with a new 
name 
-       // at a new depth.
-       {
-           character* ch = m_display_list.get_character_by_name(name);
-           if (ch)
-               {
-                   array<swf_event*>   dummy_event_handlers;
+                                   swf_event*  ev = new swf_event;
+                                   ev->read(in, this_flags);
 
-                   add_display_object(
-                       ch->get_id(),
-                       newname.c_str(),
-                       dummy_event_handlers,
-                       depth,
-                       true,   // replace if depth is occupied
-                       ch->get_cxform(),
-                       ch->get_matrix(),
-                       ch->get_ratio(),
-                       ch->get_clip_depth());
-                   // @@ TODO need to duplicate ch's event handlers, and 
presumably other members?
-                   // Probably should make a character::clone() function to 
handle this.
-               }
-       }
+                                   m_event_handlers.push_back(ev);
+                               }
+                       }
 
 
-    void       remove_display_object(const tu_string& name)
-       // Remove the object with the specified name.
-       {
-           character* ch = m_display_list.get_character_by_name(name);
-           if (ch)
-               {
-                   // @@ TODO: should only remove movies that were created via 
clone_display_object --
-                   // apparently original movies, placed by anim events, are 
immune to this.
-                   remove_display_object(ch->get_depth(), ch->get_id());
+                   if (has_char == true && flag_move == true)
+                       {
+                           // Remove whatever's at m_depth, and put 
m_character there.
+                           m_place_type = REPLACE;
+                       }
+                   else if (has_char == false && flag_move == true)
+                       {
+                           // Moves the object at m_depth to the new location.
+                           m_place_type = MOVE;
+                       }
+                   else if (has_char == true && flag_move == false)
+                       {
+                           // Put m_character at m_depth.
+                           m_place_type = PLACE;
+                       }
+                                
+                   //log_msg("place object at depth %i\n", m_depth);
                }
        }
 
                
-    /* sprite_instance */
-    virtual bool       on_event(event_id id)
-       // Dispatch event handler(s), if any.
+    void       execute(movie* m)
+       // Place/move/whatever our object in the given movie.
        {
-           // Keep m_as_environment alive during any method calls!
-           smart_ptr<as_object_interface>      this_ptr(this);
-
-           bool called = false;
-                       
-           // First, check for built-in event handler.
-           {
-               as_value        method;
-               if (get_event_handler(id, &method))
-                   {
-                       // Dispatch.
-                       call_method0(method, &m_as_environment, this);
-
-                       called = true;
-                       // Fall through and call the function also, if it's 
defined!
-                       // (@@ Seems to be the behavior for mouse events; not 
tested & verified for
-                       // every event type.)
-                   }
-           }
-
-           // Check for member function.
-           {
-               // In ActionScript 2.0, event method names are CASE SENSITIVE.
-               // In ActionScript 1.0, event method names are CASE INSENSITIVE.
-               const tu_stringi&       method_name = 
id.get_function_name().to_tu_stringi();
-               if (method_name.length() > 0)
-                   {
-                       as_value        method;
-                       if (get_member(method_name, &method))
-                           {
-                               call_method0(method, &m_as_environment, this);
-                               called = true;
-                           }
-                   }
+           switch (m_place_type) {
+             case PLACE:
+                 m->add_display_object(
+                     m_character_id,
+                     m_name,
+                     m_event_handlers,
+                     m_depth,
+                     m_tag_type != 4,  // original place_object doesn't do 
replacement
+                     m_color_transform,
+                     m_matrix,
+                     m_ratio,
+                     m_clip_depth);
+                 break;
+                 
+             case MOVE:
+                 m->move_display_object(
+                     m_depth,
+                     m_has_cxform,
+                     m_color_transform,
+                     m_has_matrix,
+                     m_matrix,
+                     m_ratio,
+                     m_clip_depth);
+                 break;
+                 
+             case REPLACE:
+                 m->replace_display_object(
+                     m_character_id,
+                     m_name,
+                     m_depth,
+                     m_has_cxform,
+                     m_color_transform,
+                     m_has_matrix,
+                     m_matrix,
+                     m_ratio,
+                     m_clip_depth);
+                 break;
            }
-
-           return called;
-       }
-
-
-    /*sprite_instance*/
-    virtual void       on_event_load()
-       // Do the events that (appear to) happen as the movie
-       // loads.  frame1 tags and actions are executed (even
-       // before advance() is called).  Then the onLoad event
-       // is triggered.
-       {
-           execute_frame_tags(0);
-           do_actions();
-           on_event(event_id::LOAD);
-       }
-
-    // Do the events that happen when there is XML data waiting
-    // on the XML socket connection.
-    virtual void       on_event_xmlsocket_onxml()
-       {
-           log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
-           on_event(event_id::SOCK_XML);
        }
-               
-    // Do the events that (appear to) happen on a specified interval.
-    virtual void       on_event_interval_timer()
-       {
-           log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
-           on_event(event_id::TIMER);
-       }
-
-    // Do the events that happen as a MovieClip (swf 7 only) loads.
-    virtual void       on_event_load_progress()
+    
+    void       execute_state(movie* m)
        {
-           log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
-           on_event(event_id::LOAD_PROGRESS);
+           execute(m);
        }
-
-    /*sprite_instance*/
-    virtual const char*        call_method_args(const char* method_name, const 
char* method_arg_fmt, va_list args)
+    
+    void       execute_state_reverse(movie* m, int frame)
        {
-           // Keep m_as_environment alive during any method calls!
-           smart_ptr<as_object_interface>      this_ptr(this);
-
-           return call_method_parsed(&m_as_environment, this, method_name, 
method_arg_fmt, args);
+           switch (m_place_type) {
+             case PLACE:
+                 // reverse of add is remove
+                 m->remove_display_object(m_depth, m_tag_type == 4 ? 
m_character_id : -1);
+                 break;
+                 
+             case MOVE:
+                 // reverse of move is move
+                 m->move_display_object(
+                     m_depth,
+                     m_has_cxform,
+                     m_color_transform,
+                     m_has_matrix,
+                     m_matrix,
+                     m_ratio,
+                     m_clip_depth);
+                 break;
+                 
+             case REPLACE:
+             {
+                 // reverse of replace is to re-add the previous object.
+                 execute_tag*  last_add = 
m->find_previous_replace_or_add_tag(frame, m_depth, -1);
+                 if (last_add) {
+                     last_add->execute_state(m);
+                 } else {
+                     log_error("reverse REPLACE can't find previous replace or 
add tag(%d, %d)\n",
+                               frame, m_depth);
+                     
+                 }
+                 break;
+             }
+           }
        }
-
-    /* sprite_instance */
-    virtual void       attach_display_callback(const char* path_to_object, 
void (*callback)(void*), void* user_ptr)
+    
+    virtual uint32     get_depth_id_of_replace_or_add_tag() const
+       // "depth_id" is the 16-bit depth & id packed into one 32-bit int.
        {
-           assert(m_parent == NULL);   // should only be called on the root 
movie.
-
-           array<with_stack_entry>     dummy;
-           as_value    obj = 
m_as_environment.get_variable(tu_string(path_to_object), dummy);
-           as_object_interface*        as_obj = obj.to_object();
-           if (as_obj)
+           if (m_place_type == PLACE || m_place_type == REPLACE)
                {
-                   movie*      m = as_obj->to_movie();
-                   if (m)
+                   int id = -1;
+                   if (m_tag_type == 4)
                        {
-                           m->set_display_callback(callback, user_ptr);
+                           // Old-style PlaceObject; the corresponding Remove
+                           // is specific to the character_id.
+                           id = m_character_id;
                        }
+                   return ((m_depth & 0x0FFFF) << 16) | (id & 0x0FFFF);
+               }
+           else
+               {
+                   return (uint32) -1;
                }
        }
 };
 
 
-character*     sprite_definition::create_character_instance(movie* parent, int 
id)
-    // Create a (mutable) instance of our definition.  The
-    // instance is created to live (temporarily) on some level on
-    // the parent movie's display list.
+       
+void   place_object_2_loader(stream* in, int tag_type, movie_definition_sub* m)
 {
-    sprite_instance*   si = new sprite_instance(this, parent->get_root(), 
parent, id);
+    assert(tag_type == 4 || tag_type == 26);
+
+    IF_VERBOSE_PARSE(log_msg("  place_object_2\n"));
 
-    return si;
+    place_object_2*    ch = new place_object_2;
+    ch->read(in, tag_type, m->get_version());
+
+    m->add_execute_tag(ch);
 }
 
 
-movie_interface*       movie_def_impl::create_instance()
-    // Create a playable movie instance from a def.
-{
-    movie_root*        m = new movie_root(this);
-    assert(m);
 
-    sprite_instance*   root_movie = new sprite_instance(this, m, NULL, -1);
-    assert(root_movie);
 
-    root_movie->set_name("_root");
-    m->set_root_movie(root_movie);
 
-    m->add_ref();
-    return m;
-}
 
 
 void   sprite_loader(stream* in, int tag_type, movie_definition_sub* m)
@@ -4615,170 +1768,6 @@
 }
 
 
-//
-// sprite built-in ActionScript methods
-//
-
-void   sprite_play(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-    sprite->set_play_state(movie_interface::PLAY);
-}
-
-void   sprite_stop(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-    sprite->set_play_state(movie_interface::STOP);
-}
-
-void   sprite_goto_and_play(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    if (fn.nargs < 1)
-       {
-           log_error("error: sprite_goto_and_play needs one arg\n");
-           return;
-       }
-
-    int        target_frame = int(fn.arg(0).to_number() - 1);  // Convert to 
0-based
-
-    sprite->goto_frame(target_frame);
-    sprite->set_play_state(movie_interface::PLAY);
-}
-
-void   sprite_goto_and_stop(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    if (fn.nargs < 1)
-       {
-           log_error("error: sprite_goto_and_stop needs one arg\n");
-           return;
-       }
-
-    int        target_frame = int(fn.arg(0).to_number() - 1);  // Convert to 
0-based
-
-    sprite->goto_frame(target_frame);
-    sprite->set_play_state(movie_interface::STOP);
-}
-
-void   sprite_next_frame(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    int frame_count = sprite->get_frame_count();
-    int current_frame = sprite->get_current_frame();
-    if (current_frame < frame_count)
-       {
-           sprite->goto_frame(current_frame + 1);
-       }
-    sprite->set_play_state(movie_interface::STOP);
-}
-
-void   sprite_prev_frame(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    int current_frame = sprite->get_current_frame();
-    if (current_frame > 0)
-       {
-           sprite->goto_frame(current_frame - 1);
-       }
-    sprite->set_play_state(movie_interface::STOP);
-}
-
-void   sprite_get_bytes_loaded(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    fn.result->set_int(sprite->get_root()->get_file_bytes());
-}
-
-void   sprite_get_bytes_total(const fn_call& fn)
-{
-    sprite_instance* sprite = (sprite_instance*) fn.this_ptr;
-    if (sprite == NULL)
-       {
-           sprite = (sprite_instance*) fn.env->get_target();
-       }
-    assert(sprite);
-
-    fn.result->set_int(sprite->get_root()->get_file_bytes());
-}
-
-
-static void    sprite_builtins_init()
-{
-    if (s_sprite_builtins)
-       {
-           return;
-       }
-
-    s_sprite_builtins = new as_object;
-    s_sprite_builtins->set_member("play", &sprite_play);
-    s_sprite_builtins->set_member("stop", &sprite_stop);
-    s_sprite_builtins->set_member("gotoAndStop", &sprite_goto_and_stop);
-    s_sprite_builtins->set_member("gotoAndPlay", &sprite_goto_and_play);
-    s_sprite_builtins->set_member("nextFrame", &sprite_next_frame);
-    s_sprite_builtins->set_member("prevFrame", &sprite_prev_frame);
-    s_sprite_builtins->set_member("getBytesLoaded", &sprite_get_bytes_loaded);
-    s_sprite_builtins->set_member("getBytesTotal", &sprite_get_bytes_loaded);
-
-    // @TODO
-//             s_sprite_builtins->set_member("startDrag", &sprite_start_drag);
-//             s_sprite_builtins->set_member("stopDrag", &sprite_stop_drag);
-//             s_sprite_builtins->set_member("getURL", &sprite_get_url);
-//             s_sprite_builtins->set_member("swapDepths", 
&sprite_swap_depths);
-}
-
-static void    sprite_builtins_clear()
-{
-    if (s_sprite_builtins)
-       {
-           delete s_sprite_builtins;
-           s_sprite_builtins = 0;
-       }
-}
-
-
-
-
 
 //
 // end_tag
Index: gnash/server/impl.h
diff -u gnash/server/impl.h:1.3 gnash/server/impl.h:1.4
--- gnash/server/impl.h:1.3     Tue Jan 24 01:33:02 2006
+++ gnash/server/impl.h Wed Jan 25 18:03:25 2006
@@ -33,8 +33,6 @@
 #include "smart_ptr.h"
 #include <stdarg.h>
 
-namespace jpeg { struct input; }
-
 namespace gnash {
        struct action_buffer;
        struct bitmap_character_def;
@@ -647,7 +645,9 @@
        // to call this in order to handle special tag types.
        typedef void (*loader_function)(stream* input, int tag_type, 
movie_definition_sub* m);
        void    register_tag_loader(int tag_type, loader_function lf);
-       
+
+       // These are the registered tag loaders
+       extern hash<int, loader_function> s_tag_loaders;
        
        // Tag loader functions.
        void    null_loader(stream* in, int tag_type, movie_definition_sub* m);
@@ -679,6 +679,40 @@
        // sound_stream_loader();       // head, head2, block
 
 
+       //
+       // swf_event
+       //
+       // For embedding event handlers in place_object_2
+
+       struct swf_event
+       {
+           // NOTE: DO NOT USE THESE AS VALUE TYPES IN AN
+           // array<>!  They cannot be moved!  The private
+           // operator=(const swf_event&) should help guard
+           // against that.
+
+           event_id    m_event;
+           action_buffer       m_action_buffer;
+           as_value    m_method;
+
+           swf_event()
+               {
+               }
+
+           void        attach_to(character* ch) const
+               {
+                   ch->set_event_handler(m_event, m_method);
+               }
+
+               void read(stream* in, Uint32 flags);
+
+       private:
+           // DON'T USE THESE
+           swf_event(const swf_event& s) { assert(0); }
+           void        operator=(const swf_event& s) { assert(0); }
+       };
+
+
 }      // end namespace gnash
 
 




reply via email to

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