gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash ./ChangeLog server/dlist.cpp server/dlist...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ./ChangeLog server/dlist.cpp server/dlist...
Date: Mon, 29 May 2006 12:49:34 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Branch:         
Changes by:     Sandro Santilli <address@hidden>        06/05/29 12:49:34

Modified files:
        .              : ChangeLog 
        server         : dlist.cpp dlist.h sprite_instance.cpp 
                         sprite_instance.h 

Log message:
        * server/dlist.h, server/dlist.cpp: renamed display_list
        to DisplayList and made a real class, many functions moved
        to private space, abstracted underlying container to allow
        for future modifications aimed at performance improvements;
        current implementation done with std::list.
        * server/sprite_instance.h, server/sprite_instance.cpp:
        updated to use the new DisplayList class interface.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/ChangeLog.diff?tr1=1.384&tr2=1.385&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/dlist.cpp.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/dlist.h.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/sprite_instance.cpp.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/sprite_instance.h.diff?tr1=1.4&tr2=1.5&r1=text&r2=text

Patches:
Index: gnash/ChangeLog
diff -u gnash/ChangeLog:1.384 gnash/ChangeLog:1.385
--- gnash/ChangeLog:1.384       Sat May 27 18:46:09 2006
+++ gnash/ChangeLog     Mon May 29 12:49:34 2006
@@ -1,4 +1,15 @@
+2006-05-29 Sandro Santilli <address@hidden>
+
+       * server/dlist.h, server/dlist.cpp: renamed display_list
+       to DisplayList and made a real class, many functions moved
+       to private space, abstracted underlying container to allow
+       for future modifications aimed at performance improvements;
+       current implementation done with std::list.
+       * server/sprite_instance.h, server/sprite_instance.cpp:
+       updated to use the new DisplayList class interface.
+
 2006-05-27 Vitaly Alexeev <address@hidden>
+
        * server/action.h: updated forward declaration.
        * server/resource.h: updated forward declaration.
        * server/fn_call.h: updated forward declaration.
Index: gnash/server/dlist.cpp
diff -u gnash/server/dlist.cpp:1.9 gnash/server/dlist.cpp:1.10
--- gnash/server/dlist.cpp:1.9  Mon May  8 21:12:24 2006
+++ gnash/server/dlist.cpp      Mon May 29 12:49:34 2006
@@ -1,598 +1,531 @@
-// dlist.cpp   -- Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// A list of active characters.
+// 
+//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
 
 #include "dlist.h"
 #include "log.h"
 #include "render.h"
 #include "gnash.h"
+
 #include <typeinfo>
+#include <iostream>
+#include <algorithm>
 
 namespace gnash {
-       /*static*/ int  display_object_info::compare(const void* _a, const 
void* _b)
-       {
-               const display_object_info*      a = (const 
display_object_info*) _a;
-               const display_object_info*      b = (const 
display_object_info*) _b;
 
-               if (a->m_character->get_depth() < b->m_character->get_depth())
-               {
-                       return -1;
-               }
-               else if (a->m_character->get_depth() == 
b->m_character->get_depth())
-               {
-                       return 0;
-               }
-               else
-               {
-                       return 1;
-               }
-       }
+struct DepthEquals {
 
-       
-       int     display_list::find_display_index(int depth)
-       // Find the index in the display list of the first object
-       // matching the given depth.  Failing that, return the index
-       // of the first object with a larger depth.
-       {
-               int     size = m_display_object_array.size();
-               if (size == 0)
-               {
-                       return 0;
-               }
-               
-               // Binary search.
-               int     jump = size >> 1;
-               int     index = jump;
-               for (;;)
-               {
-                       jump >>= 1;
-                       if (jump < 1) jump = 1;
-                       
-                       if (depth > 
m_display_object_array[index].m_character->get_depth())
-                       {
-                               if (index == size - 1)
-                               {
-                                       index = size;
-                                       break;
-                               }
-                               index += jump;
-                       }
-                       else if (depth < 
m_display_object_array[index].m_character->get_depth())
-                       {
-                               if (index == 0
-                                   || depth > m_display_object_array[index - 
1].m_character->get_depth())
-                               {
-                                       break;
-                               }
-                               index -= jump;
-                       }
-                       else
-                       {
-                               // match -- scan backward to make sure this is 
the first entry with this depth.
-                               //
-                               // Linear.  But multiple objects with the same 
depth are only allowed for
-                               // very old SWF's, so we don't really care.
-                               for (;;)
-                               {
-                                       if (index == 0
-                                           || m_display_object_array[index - 
1].m_character->get_depth() < depth)
-                                       {
-                                               break;
-                                       }
-                                       index--;
-                               }
-                               
assert(m_display_object_array[index].m_character->get_depth() == depth);
-                               assert(index == 0 || 
m_display_object_array[index - 1].m_character->get_depth() < depth);
-                               break;
-                       }
-               }
-               
-               assert(index >= 0 && index <= size);
-               
-               return index;
-       }
-       
+       int _depth;
 
-       int     display_list::get_display_index(int depth)
-               // Like the above, but looks for an exact match, and returns -1 
if failed.
-       {
-               int     index = find_display_index(depth);
-               if (index >= (int) m_display_object_array.size()
-                       || get_display_object(index).m_character->get_depth() 
!= depth)
-               {
-                       // No object at that depth.
-                       return -1;
-               }
-               return index;
+       DepthEquals(int depth)
+               :
+               _depth(depth)
+       {}
+
+       bool operator() (const DisplayItem& item) {
+               if ( ! item.get_ptr() ) return false;
+               return item->get_depth() == _depth;
        }
+};
 
+struct DepthGreaterOrEqual {
 
-       character*      display_list::get_character_at_depth(int depth)
-       {
-               int     index = get_display_index(depth);
-               if (index != -1)
-               {
-                       character*      ch = 
m_display_object_array[index].m_character.get_ptr();
-                       if (ch->get_depth() == depth)
-                       {
-                               return ch;
-                       }
-               }
+       int _depth;
+
+       DepthGreaterOrEqual(int depth)
+               :
+               _depth(depth)
+       {}
 
-               return NULL;
+       bool operator() (const DisplayItem& item) {
+               if ( ! item.get_ptr() ) return false;
+               return item->get_depth() >= _depth;
        }
+};
 
+struct NameEquals {
 
-       character*      display_list::get_character_by_name(const tu_string& 
name)
-       {
-               // See if we have a match on the display list.
-               for (int i = 0, n = get_character_count(); i < n; i++)
-               {
-                       character*      ch = get_character(i);
-                       if (ch->get_name() == name.c_str())
-                       {
-                               // Found it.
-                               return ch;
-                       }
-               }
-               return NULL;
+       const tu_string& _name;
+
+       NameEquals(const tu_string& name)
+               :
+               _name(name)
+       {}
+
+       bool operator() (const DisplayItem& item) {
+               if ( ! item.get_ptr() ) return false;
+               return item->get_name() == _name;
        }
+};
 
-       character*      display_list::get_character_by_name_i(const tu_stringi& 
name)
-       // Return first character with matching (case insensitive) name, if any.
-       {
-               // Search through dlist for a match.
-               for (int i = 0, n = get_character_count(); i < n; i++)
-               {
-                       character*      ch = get_character(i);
-                       if (name == ch->get_name().c_str())
-                       {
-                               // Found it.
-                               return ch;
-                       }
-               }
+struct NameEqualsNoCase {
 
-               return NULL;
+       const tu_stringi& _name;
+
+       NameEqualsNoCase(const tu_stringi& name)
+               :
+               _name(name)
+       {}
+
+       bool operator() (const DisplayItem& item) {
+               if ( ! item.get_ptr() ) return false;
+               return item->get_name() == _name;
        }
+};
 
+character*
+DisplayList::get_character_at_depth(int depth)
+{
+       //GNASH_REPORT_FUNCTION;
+       //dump(std::cout);
 
-       void    display_list::add_display_object(
-               character* ch, 
-               uint16_t depth,
-               bool replace_if_depth_is_occupied,
-               const cxform& color_xform, 
-               const matrix& mat, 
-               float ratio,
-               uint16_t clip_depth)
+       for (iterator it = _characters.begin(),
+                       itEnd = _characters.end();
+               it != itEnd; ++it)
        {
-//         GNASH_REPORT_FUNCTION;
-//             IF_VERBOSE_DEBUG(log_msg("dl::add(%d, '%s')\n", depth, 
ch->get_name()));//xxxxx
+               character* ch = it->get_ptr();
+               assert(ch); // is this really needed ?
 
-               assert(ch);
-               
-               int     size = m_display_object_array.size();
-               int index = find_display_index(depth);
+               // found
+               if ( ch->get_depth() == depth ) return ch;
 
-               if (replace_if_depth_is_occupied)
-               {
-                       // Eliminate an existing object if it's in the way.
-                       if (index >= 0 && index < size)
-                       {
-                               display_object_info & dobj = 
m_display_object_array[index];
+               // non-existent (chars are ordered by depth)
+               if ( ch->get_depth() > depth ) return NULL;
+       }
 
-                               if (dobj.m_character->get_depth() == depth)
-                               {
-                                       dobj.set_character(NULL);
-                                       
m_display_object_array.erase(m_display_object_array.begin() + index);
-                               }
-                       }
-               }
-               else
-               {
-                       // Caller wants us to allow multiple objects
-                       // with the same depth.  find_display_index()
-                       // returns the first matching depth, if there
-                       // are any, so the new character will get
-                       // inserted before all the others with the
-                       // same depth.  This matches the semantics
-                       // described by Alexi's SWF ref.  (This is all
-                       // for legacy SWF compatibility anyway.)
-               }
+       return NULL;
 
-               ch->set_depth(depth);
+}
 
-               display_object_info     di;
-               di.m_ref = true;
-               di.set_character(ch);
-               di.m_character->set_depth(depth);
-               di.m_character->set_cxform(color_xform);
-               di.m_character->set_matrix(mat);
-               di.m_character->set_ratio(ratio);
-               di.m_character->set_clip_depth(clip_depth);
 
-               // Insert into the display list...
-               assert(index == find_display_index(depth));
-               
-               m_display_object_array.insert(m_display_object_array.begin() + 
index, di);
+character*
+DisplayList::get_character_by_name(const tu_string& name)
+{
+       container_type::iterator it = find_if(
+                       _characters.begin(),
+                       _characters.end(),
+                       NameEquals(name));
 
-               // do the frame1 actions (if applicable) and the "onClipEvent 
(load)" event.
-               ch->on_event_load();
-       }
-       
-       
-       void    display_list::move_display_object(
-               uint16_t depth,
-               bool use_cxform,
-               const cxform& color_xform,
-               bool use_matrix,
-               const matrix& mat,
-               float ratio,
-               uint16_t clip_depth)
-       // Updates the transform properties of the object at
-       // the specified depth.
-       {
-//             IF_VERBOSE_DEBUG(log_msg("dl::move(%d)\n", depth));//xxxxx
+       if ( it == _characters.end() ) return NULL;
+       else return it->get_ptr();
 
-               int     size = m_display_object_array.size();
-               if (size <= 0)
-               {
-                       // error.
-                       log_error("error: move_display_object() -- no objects 
on display list\n");
-                       //                      assert(0);
-                       return;
-               }
-               
-               int     index = find_display_index(depth);
-               if (index < 0 || index >= size)
-               {
-                       // error.
-                       log_error("error: move_display_object() -- can't find 
object at depth %d\n", depth);
-                       //                      assert(0);
-                       return;
-               }
-               
-               display_object_info&    di = m_display_object_array[index];
-               character*      ch = di.m_character.get_ptr();
-               if (ch->get_depth() != depth)
-               {
-                       // error
-                       log_error("error: move_display_object() -- no object at 
depth %d\n", depth);
-                       //                      assert(0);
-                       return;
-               }
+}
 
-               di.m_ref = true;
+character*
+DisplayList::get_character_by_name_i(const tu_stringi& name)
+{
+       container_type::iterator it = find_if(
+                       _characters.begin(),
+                       _characters.end(),
+                       NameEqualsNoCase(name));
 
-               if (ch->get_accept_anim_moves() == false)
-               {
-                       // This character is rejecting anim moves.  This 
happens after it
-                       // has been manipulated by ActionScript.
-                       return;
-               }
+       if ( it == _characters.end() ) return NULL;
+       else return it->get_ptr();
+}
 
-               if (use_cxform)
-               {
-                       ch->set_cxform(color_xform);
-               }
-               if (use_matrix)
-               {
-                       ch->set_matrix(mat);
-               }
-               ch->set_ratio(ratio);
-               // move_display_object apparently does not change clip depth!  
Thanks to Alexeev Vitaly.
-               // ch->set_clip_depth(clip_depth);
-       }
-       
-       
-       void    display_list::replace_display_object(
-               character* ch,
-               uint16_t depth,
-               bool use_cxform,
-               const cxform& color_xform,
-               bool use_matrix,
-               const matrix& mat,
-               float ratio,
-               uint16_t clip_depth)
-       // Puts a new character at the specified depth, replacing any
-       // existing character.  If use_cxform or use_matrix are false,
-       // then keep those respective properties from the existing
-       // character.
-       {
-//             IF_VERBOSE_DEBUG(log_msg("dl::replace(%d)\n", depth));//xxxxx
-
-               int     size = m_display_object_array.size();
-               int     index = find_display_index(depth);
-               if (index < 0 || index >= size)
-               {
-                       // Error, no existing object found at depth.
-//                     IF_VERBOSE_DEBUG(log_msg("dl::replace_display_object() 
no obj at depth %d\n", depth));
-                       // Fallback -- add the object.
-                       add_display_object(ch, depth, true, color_xform, mat, 
ratio, clip_depth);
-                       return;
-               }
-               
-               display_object_info&    di = m_display_object_array[index];
-               if (di.m_character->get_depth() != depth)
-               {
-                       // error
-//                     IF_VERBOSE_DEBUG(log_msg("warning: 
replace_display_object() -- no object at depth %d\n", depth));
-                       return;
-               }
-               
-               smart_ptr<character>    old_ch = di.m_character;
 
-               // Put the new character in its place.
-               assert(ch);
-               ch->set_depth(depth);
-               ch->restart();
-               
-               // Set the display properties.
-               di.m_ref = true;
-               di.set_character(ch);
+void
+DisplayList::place_character(
+       character* ch, 
+       uint16_t depth,
+       const cxform& color_xform, 
+       const matrix& mat, 
+       float ratio,
+       uint16_t clip_depth)
+{
+       GNASH_REPORT_FUNCTION;
+       //IF_VERBOSE_DEBUG(log_msg("dl::add(%d, '%s')\n", depth, 
ch->get_name()));//xxxxx
+
+       //log_msg("Before adding, list is:");
+       //dump(std::cout);
+
+       assert(ch);
+       
+       ch->set_depth(depth);
+       ch->set_cxform(color_xform);
+       ch->set_matrix(mat);
+       ch->set_ratio(ratio);
+       ch->set_clip_depth(clip_depth);
+
+       container_type::iterator it = find_if(
+                       _characters.begin(), _characters.end(),
+                       DepthGreaterOrEqual(depth));
+
+       if ( it == _characters.end() || (*it)->get_depth() != depth )
+       {
+               //IF_VERBOSE_DEBUG(dbglogfile << "This is a new character" << 
std::endl );
+               // add the new char
+               _characters.insert(it, DisplayItem(ch));
+       }
+       else
+       {
+               //IF_VERBOSE_DEBUG(dbglogfile << "Replacing existing character" 
<< std::endl );
+               // replace existing char
+               *it = DisplayItem(ch);
+       }
+
+       // do the frame1 actions (if applicable) and the "onClipEvent (load)"
+       // event.
+       ch->on_event_load();
 
-               if (use_cxform)
-               {
-                       ch->set_cxform(color_xform);
-               }
-               else
+       //log_msg("After adding, list is:");
+       //dump(std::cout);
+}
+
+void
+DisplayList::replace_character(
+       character* ch,
+       uint16_t depth,
+       bool use_cxform,
+       const cxform& color_xform,
+       bool use_matrix,
+       const matrix& mat,
+       float ratio,
+       uint16_t clip_depth)
+{
+       GNASH_REPORT_FUNCTION;
+
+       ch->set_depth(depth);
+       ch->set_cxform(color_xform);
+       ch->set_matrix(mat);
+       ch->set_ratio(ratio);
+       ch->set_clip_depth(clip_depth);
+       ch->restart();
+
+       container_type::iterator it = find_if(
+                       _characters.begin(), _characters.end(),
+                       DepthGreaterOrEqual(depth));
+
+       DisplayItem di(ch);
+
+       if ( it == _characters.end() || (*it)->get_depth() != depth )
+       {
+
+               // Error, no existing object found at depth.
+//             IF_VERBOSE_DEBUG(
+//                     log_msg("dl::replace_display_object()"
+//                             " no obj at depth %d\n", depth)
+//             );
+
+               // add the new char
+               _characters.insert(it, di);
+
+               // do the frame1 actions (if applicable) and the
+               // "onClipEvent (load)" event.
+               ch->on_event_load();
+       }
+       else
+       {
+               if (!use_cxform)
                {
                        // Use the cxform from the old character.
-                       ch->set_cxform(old_ch->get_cxform());
+                       ch->set_cxform((*it)->get_cxform());
                }
 
-               if (use_matrix)
-               {
-                       ch->set_matrix(mat);
-               }
-               else
+               if (!use_matrix)
                {
                        // Use the matrix from the old character.
-                       ch->set_matrix(old_ch->get_matrix());
+                       ch->set_matrix((*it)->get_matrix());
                }
 
-               ch->set_ratio(ratio);
-               ch->set_clip_depth(clip_depth);
+               // replace existing char
+               *it = di;
        }
+
+}
        
        
-       void    display_list::remove_display_object(uint16_t depth, int id)
-       // Removes the object at the specified depth.
-       {
-//             IF_VERBOSE_DEBUG(log_msg("dl::remove(%d)\n", depth));//xxxxx
+// Updates the transform properties of the object at
+// the specified depth.
+void
+DisplayList::move_display_object(
+       uint16_t depth,
+       bool use_cxform,
+       const cxform& color_xform,
+       bool use_matrix,
+       const matrix& mat,
+       float ratio,
+       uint16_t clip_depth)
+{
+       //GNASH_REPORT_FUNCTION;
+       //IF_VERBOSE_DEBUG(log_msg("dl::move(%d)\n", depth));//xxxxx
 
-               int     size = m_display_object_array.size();
-               if (size <= 0)
-               {
-                       // error.
-                       log_error("remove_display_object: no characters in 
display list\n");
-                       return;
-               }
-               
-               int     index = find_display_index(depth);
-               if (index < 0
-                   || index >= size
-                   || get_character(index)->get_depth() != depth)
-               {
-                       // error -- no character at the given depth.
-                       log_error("remove_display_object: no character at depth 
%d\n", depth);
-                       return;
-               }
-
-               assert(get_character(index)->get_depth() == depth);
-               
-               if (id != -1)
-               {
-                       // Caller specifies a specific id; scan forward til we 
find it.
-                       for (;;)
-                       {
-                               if (get_character(index)->get_id() == id)
-                               {
-                                       break;
-                               }
-                               if (index + 1 >= size
-                                   || get_character(index + 1)->get_depth() != 
depth)
-                               {
-                                       // Didn't find a match!
-                                       log_error("remove_display_object: no 
character at depth %d with id %d\n", depth, id);
-                                       return;
-                               }
-                               index++;
-                       }
-                       assert(index < size);
-                       assert(get_character(index)->get_depth() == depth);
-                       assert(get_character(index)->get_id() == id);
-               }
+       character* ch = get_character_at_depth(depth);
+       if ( ! ch )
+       {
+               log_error("error: move_display_object() -- "
+                       "can't find object at depth %d\n",
+                       depth);
+               return;
+       }
 
-               // Removing the character at get_display_object(index).
-               display_object_info&    di = m_display_object_array[index];
-               
-               // Remove reference only.
-               di.m_ref = false;
+       if (ch->get_accept_anim_moves() == false)
+       {
+               // This character is rejecting anim moves.  This happens after 
it
+               // has been manipulated by ActionScript.
+               return;
        }
-       
-       
-       void    display_list::clear()
-       // clear the display list.
+
+       if (use_cxform)
        {
-               int i, n = m_display_object_array.size();
-               for (i = 0; i < n; i++)
-               {
-                       display_object_info&    di = m_display_object_array[i];
-                       //character*    ch = 
m_display_object_array[i].m_character;
-                       di.m_character->on_event(event_id::UNLOAD);
-               }
-               
-               m_display_object_array.clear();
+               ch->set_cxform(color_xform);
        }
-       
-       
-       void    display_list::reset()
-       // reset the references to the display list.
+       if (use_matrix)
        {
-               //printf("### reset the display list!\n");
-               int i, n = m_display_object_array.size();
-               for (i = 0; i < n; i++)
-               {
-                       m_display_object_array[i].m_ref = false;
-               }
+               ch->set_matrix(mat);
        }
+       ch->set_ratio(ratio);
+       // move_display_object apparently does not change clip depth!  Thanks 
to Alexeev Vitaly.
+       // ch->set_clip_depth(clip_depth);
+}
        
        
-       void    display_list::update()
-       // remove unreferenced objects.
-       {
-               //printf("### update the display list!\n");
-               
-               int r = 0;
-               int i, n = m_display_object_array.size();
-               for (i = n-1; i >= 0; i--)
-               {
-                       display_object_info & dobj = m_display_object_array[i];
-                       
-                       if (dobj.m_ref == false)
-                       {
-                               dobj.set_character(NULL);
+// Removes the object at the specified depth.
+void
+DisplayList::remove_display_object(uint16_t depth)
+{
+       GNASH_REPORT_FUNCTION;
+
+       //log_msg("Before removing, list is:");
+       //dump(std::cout);
+
+#ifndef NDEBUG
+       container_type::size_type size = _characters.size();
+#endif
+
+       // TODO: optimize to take by-depth order into account
+       container_type::iterator new_end = remove_if(
+                       _characters.begin(),
+                       _characters.end(),
+                       DepthEquals(depth));
+
+       if ( new_end != _characters.end() ) {
+               _characters.erase(new_end, _characters.end());
+       }
+
+#ifndef NDEBUG
+       assert(size >= _characters.size());
+#endif
 
-                               
m_display_object_array.erase(m_display_object_array.begin() + i);
-                               r++;
-                       }
-               }
-               
-               //printf("### removed characters: %4d active characters: 
%4d\n", r, m_display_object_array.size());
+       //log_msg("Done removing, list is:");
+       //dump(std::cout);
+}
+       
+       
+// clear the display list.
+void
+DisplayList::clear()
+{
+       GNASH_REPORT_FUNCTION;
+       for (iterator it = _characters.begin(),
+                       itEnd = _characters.end();
+               it != itEnd; ++it)
+       {
+               DisplayItem& di = *it;
+               if ( ! it->get_ptr() ) continue;
+               di->on_event(event_id::UNLOAD);
        }
+               
+       _characters.clear();
+}
        
        
-       void    display_list::advance(float delta_time)
-       // advance referenced characters.
-       {
-//             GNASH_REPORT_FUNCTION;
+// reset the references to the display list.
+void
+DisplayList::reset()
+{
+       GNASH_REPORT_FUNCTION;
+
+       // We just clear the container, but
+       // might eventually keep it allocated
+       // to reduce allocation costs.
+       _characters.clear();
+}
+       
+void
+DisplayList::advance(float delta_time)
+// advance referenced characters.
+{
+       //GNASH_REPORT_FUNCTION;
+
+       container_type::size_type size = _characters.size();
+
+       for (iterator it = _characters.begin(),
+                       itEnd = _characters.end();
+               it != itEnd; ++it)
+       {
+               // @@@@ TODO FIX: If array changes size due to
+               // character actions, the iteration may not be
+               // correct!
+               //
+               // What's the correct thing to do here?  Options:
+               //
+               // * copy the display list at the beginning,
+               // iterate through the copy
+               //
+               // * use (or emulate) a linked list instead of
+               // an array (still has problems; e.g. what
+               // happens if the next or current object gets
+               // removed from the dlist?)
+               //
+               // * iterate through current array in depth
+               // order.  Always find the next object using a
+               // search of current array (but optimize the
+               // common case where nothing has changed).
+               //
+               // * ???
+               //
+               // Need to test to see what Flash does.
 
-               int n = m_display_object_array.size();
-               for (int i = 0; i < n; i++)
+               if (_characters.size() != size)
                {
-                       // @@@@ TODO FIX: If array changes size due to
-                       // character actions, the iteration may not be
-                       // correct!
-                       //
-                       // What's the correct thing to do here?  Options:
-                       //
-                       // * copy the display list at the beginning,
-                       // iterate through the copy
-                       //
-                       // * use (or emulate) a linked list instead of
-                       // an array (still has problems; e.g. what
-                       // happens if the next or current object gets
-                       // removed from the dlist?)
-                       //
-                       // * iterate through current array in depth
-                       // order.  Always find the next object using a
-                       // search of current array (but optimize the
-                       // common case where nothing has changed).
-                       //
-                       // * ???
-                       //
-                       // Need to test to see what Flash does.
-                       if (n != (int) m_display_object_array.size())
-                       {
-                               log_error("gnash bug: dlist size changed due to 
character actions, bailing on update!\n");
-                               break;
-                       }
+                       log_error("gnash bug: dlist size changed due to 
character actions, bailing on update!\n");
+                       break;
+               }
 
-                       display_object_info & dobj = m_display_object_array[i];
-                       
-                       if (dobj.m_ref == true)
-                       {
-                               character*      ch = dobj.m_character.get_ptr();
-                               assert(ch);
+               character*      ch = it->get_ptr();
+               assert(ch);
 
-                               ch->advance(delta_time);
-                       }
-               }
+               ch->advance(delta_time);
        }
+
+}
        
        
-       void    display_list::display()
-       // Display the referenced characters. Lower depths
-       // are obscured by higher depths.
-       {
-//             GNASH_REPORT_FUNCTION;
-               
+// Display the referenced characters. Lower depths
+// are obscured by higher depths.
+void
+DisplayList::display()
+{
+       //GNASH_REPORT_FUNCTION;
+       
 //             printf(".");
 
-               bool masked = false;
-               int highest_masked_layer = 0;
-               
-               //log_msg("number of objects to be drawn %i\n", 
m_display_object_array.size());
-               
-               for (unsigned int i = 0; i < m_display_object_array.size(); i++)
-               {
-                       display_object_info&    dobj = 
m_display_object_array[i];
+       bool masked = false;
+       int highest_masked_layer = 0;
+       
+       //log_msg("number of objects to be drawn %i\n", 
m_display_object_array.size());
+       
+       for( iterator it = _characters.begin(),
+                       endIt = _characters.end();
+               it != endIt; ++it)
+       {
+               DisplayItem& dobj = *it;
 
-                       character*      ch = dobj.m_character.get_ptr();
-                       assert(ch);
+               //character*    ch = dobj.m_character.get_ptr();
+               character*      ch = dobj.get_ptr();
 
-                       if (ch->get_visible() == false)
-                       {
-                               // Don't display.
-                               continue;
-                       }
+               assert(ch);
 
-                       if (ch->get_clip_depth() > 0)
-                       {
+               if (ch->get_visible() == false)
+               {
+                       // Don't display.
+                       continue;
+               }
+
+               if (ch->get_clip_depth() > 0)
+               {
 //                             log_msg("depth %i, clip_depth %i\n", 
dobj.m_depth, dobj.m_clip_depth);
-                       }
+               }
 
-                       // check whether a previous mask should be disabled
-                       if (masked)
+               // check whether a previous mask should be disabled
+               if (masked)
+               {
+                       if (ch->get_depth() > highest_masked_layer)
                        {
-                               if (ch->get_depth() > highest_masked_layer)
-                               {
 //                                     log_msg("disabled mask before drawing 
depth %i\n", ch->get_depth());
-                                       masked = false;
-                                       // turn off mask
-                                       render::disable_mask();
-                               }
+                               masked = false;
+                               // turn off mask
+                               render::disable_mask();
                        }
+               }
 
-                       // check whether this object should become mask
-                       if (ch->get_clip_depth() > 0)
-                       {
-                               //log_msg("begin submit mask\n");
-                               render::begin_submit_mask();
-                       }
-                       
-                       ch->display();
+               // check whether this object should become mask
+               if (ch->get_clip_depth() > 0)
+               {
+                       //log_msg("begin submit mask\n");
+                       render::begin_submit_mask();
+               }
+               
+               ch->display();
 
-                       if (ch->get_clip_depth() > 0)
-                       {
+               if (ch->get_clip_depth() > 0)
+               {
 //                             log_msg("object drawn\n");
-                       }
-                       
-                       // if this object should have become a mask,
-                       // inform the renderer that it now has all
-                       // information about it
-                       if (ch->get_clip_depth() > 0)
-                       {
-                               //log_msg("end submit mask\n");
-                               render::end_submit_mask();
-                               highest_masked_layer = ch->get_clip_depth();
-                               masked = true;
-                       }
                }
                
-               if (masked)
+               // if this object should have become a mask,
+               // inform the renderer that it now has all
+               // information about it
+               if (ch->get_clip_depth() > 0)
                {
-                       // If a mask masks the scene all the way up to the 
highest
-                       // layer, it will not be disabled at the end of drawing
-                       // the display list, so disable it manually.
-                       render::disable_mask();
+                       //log_msg("end submit mask\n");
+                       render::end_submit_mask();
+                       highest_masked_layer = ch->get_clip_depth();
+                       masked = true;
                }
        }
+       
+       if (masked)
+       {
+               // If a mask masks the scene all the way up to the highest
+               // layer, it will not be disabled at the end of drawing
+               // the display list, so disable it manually.
+               render::disable_mask();
+       }
+}
+
+/*private*/
+void
+DisplayList::dump(std::ostream& os)
+{
+       int num=0;
+       for( iterator it = _characters.begin(),
+                       endIt = _characters.end();
+               it != endIt; ++it)
+       {
+               DisplayItem& dobj = *it;
+               os << "Item " << num << " at depth " << dobj->get_depth()
+                       << " (char id " << dobj->get_id() << ")" << std::endl;
+               num++;
+       }
 }
 
+} // namespace gnash
+
 
 // Local Variables:
 // mode: C++
Index: gnash/server/dlist.h
diff -u gnash/server/dlist.h:1.5 gnash/server/dlist.h:1.6
--- gnash/server/dlist.h:1.5    Mon May  8 21:12:24 2006
+++ gnash/server/dlist.h        Mon May 29 12:49:34 2006
@@ -1,9 +1,40 @@
-// dlist.h     -- Thatcher Ulrich <address@hidden> 2003
+// 
+//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
 
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// A list of active characters.
 
 
 #ifndef GNASH_DLIST_H
@@ -14,175 +45,202 @@
 #include "types.h"
 #include "impl.h"
 
+#include <list>
+#include <iosfwd>
+
 namespace gnash {
-       
-       /// A struct to serve as an entry in the display list.
-       struct display_object_info {
-               bool    m_ref;
-
-               /// state is held in here
-               smart_ptr<character>    m_character;
-               
-               display_object_info()
-                               :
-                               m_ref(false)
-               {
-               }
-               
-               display_object_info(const display_object_info& di)
-                               :
-                               m_ref(false)
-               {
-                       *this = di;
-               }
-               
-               ~display_object_info()
-               {
-               }
-               
-               void    operator=(const display_object_info& di)
-               {
-                       m_ref = di.m_ref;
-                       m_character = di.m_character;
-               }
-               
-               void    set_character(character* ch)
-               {
-                       m_character = ch;
-               }
-               
-               /// For qsort().
-               static int compare(const void* _a, const void* _b);
-       };
-
-
-       /// A list of active characters.
-       struct display_list {
-               // TODO use better names!
-               int     find_display_index(int depth);
-               int     get_display_index(int depth);
-               
-               /// Add a new character in this display list.
-               //
-               /// If applicable, the event_id::LOAD event
-               /// associated with the given character
-               /// is called as last step of addition. 
-               ///
-               /// @param ch 
-               ///     the character to be added into the list
-               ///
-               /// @param depth 
-               ///     depth to be assign to the character
-               ///     using character::set_depth
-               ///
-               /// @param replace_if_depth_is_occupied 
-               ///     If this is false, caller wants to allow multiple
-               ///     objects with the same depth.
-               ///     find_display_index() returns the first matching
-               ///     depth, if there are any, so the new character
-               ///     will get inserted before all the others with the
-               ///     same depth.  This matches the semantics
-               ///     described by Alexi's SWF ref.  (This is all
-               ///     for legacy SWF compatibility anyway.)
-               ///
-               /// @param color_xform
-               ///     Color transform to be applied to the character
-               ///     using character::set_cxform
-               ///
-               /// @param mat
-               ///     matrix to be assigned to the character
-               ///     using character::set_matrix
-               ///
-               /// @param ratio
-               ///     ratio (scale?) to be assigned to the character
-               ///     using character::set_ratio
-               ///
-               /// @param clip_depth
-               ///     clip_depth (?) to be assigned to the character
-               ///     using character::set_clip_depth
-               ///
-               void    add_display_object(
-                       character* ch,
-                       uint16_t depth,
-                       bool replace_if_depth_is_occupied,
-                       const cxform& color_xform,
-                       const matrix& mat,
-                       float ratio,
-                       uint16_t clip_depth);
-
-               /// Updates the transform properties of the object at
-               /// the specified depth.
-               void    move_display_object(
-                       uint16_t depth,
-                       bool use_cxform,
-                       const cxform& color_xform,
-                       bool use_matrix,
-                       const matrix& mat,
-                       float ratio,
-                       uint16_t clip_depth);
-
-               /// Puts a new character at the specified depth, replacing any
-               /// existing character.  If use_cxform or use_matrix are false,
-               /// then keep those respective properties from the existing
-               /// character.
-               void    replace_display_object(
-                       character* ch,
-                       uint16_t depth,
-                       bool use_cxform,
-                       const cxform& color_xform,
-                       bool use_matrix,
-                       const matrix& mat,
-                       float ratio,
-                       uint16_t clip_depth);
-
-               /// Removes the object at the specified depth.
-               void    remove_display_object(uint16_t depth, int id);
-
-               /// clear the display list.
-               void    clear();
-
-               /// reset the references to the display list.
-               void    reset();
-
-               /// remove unreferenced objects.
-               void    update();
-
-               /// advance referenced characters.
-               void    advance(float delta_time);
-
-               /// Display the referenced characters.
-               /// Lower depths are obscured by higher depths.
-               void    display();
-
-               // unused
-               //void  display(const display_info& di);
-               
-               int     get_character_count() { return 
m_display_object_array.size(); }
-               character*      get_character(int index) { return 
m_display_object_array[index].m_character.get_ptr(); }
-
-               // May return NULL.
-               character*      get_character_at_depth(int depth);
-
-               // May return NULL.
-               // If there are multiples, returns the *first* match only!
-               character*      get_character_by_name(const tu_string& name);
-
-               // May return NULL.
-               // If there are multiples, returns the *first* match only!
-               character*      get_character_by_name_i(const tu_stringi& name);
 
-               inline const display_object_info&       get_display_object(int 
idx) const
-               // get the display object at the given position.
+/// A DisplayItem is simply a character object 
+typedef smart_ptr<character> DisplayItem;
+
+/// A list of on-stage characters, ordered by depth
+//
+/// Any sprite_instance has an associated DisplayList
+/// that may change from frame to frame due to control
+/// tags instructing when to add or remove characthers
+/// from the stage.
+///
+class DisplayList {
+
+public:
+
+       /// \brief
+       /// Place a new character in this display list
+       /// replacing any other char at the same depth.
+       //
+       /// If applicable, the event_id::LOAD event
+       /// associated with the given character
+       /// is called as last step of addition. 
+       ///
+       /// @param ch 
+       ///     the character to be added into the list
+       ///
+       /// @param depth 
+       ///     depth to be assign to the character
+       ///     using character::set_depth
+       ///
+       /// @param color_xform
+       ///     Color transform to be applied to the character
+       ///     using character::set_cxform
+       ///
+       /// @param mat
+       ///     matrix to be assigned to the character
+       ///     using character::set_matrix
+       ///
+       /// @param ratio
+       ///     ratio (scale?) to be assigned to the character
+       ///     using character::set_ratio
+       ///
+       /// @param clip_depth
+       ///     clip_depth (?) to be assigned to the character
+       ///     using character::set_clip_depth
+       ///
+       void    place_character(
+               character* ch,
+               uint16_t depth,
+               const cxform& color_xform,
+               const matrix& mat,
+               float ratio,
+               uint16_t clip_depth);
+
+       /// \brief
+       /// Puts a new character at the specified depth, replacing any
+       /// existing character.
+       //
+       /// If use_cxform or use_matrix are false, and a character is
+       /// present at the given depth, then keep those respective
+       /// properties from the existing character.
+       ///
+       /// TODO: use pointers for matrix and cxform, and use NULL
+       ///       instead of the two bool arguments
+       ///
+       void replace_character(
+               character* ch,
+               uint16_t depth,
+               bool use_cxform,
+               const cxform& color_xform,
+               bool use_matrix,
+               const matrix& mat,
+               float ratio,
+               uint16_t clip_depth);
+
+
+       /// Updates the transform properties of the object at
+       /// the specified depth.
+       void    move_display_object(
+               uint16_t depth,
+               bool use_cxform,
+               const cxform& color_xform,
+               bool use_matrix,
+               const matrix& mat,
+               float ratio,
+               uint16_t clip_depth);
+
+       /// Removes the object at the specified depth.
+       void    remove_display_object(uint16_t depth);
+
+       /// \brief
+       /// Clear the display list, calling the UNLOAD event
+       /// on each item still present
+       void clear();
+
+       /// \brief
+       /// Clear the display list, w/out calling the UNLOAD event
+       /// on the items.
+       void reset();
+
+       /// advance referenced characters.
+       void advance(float delta_time);
+
+       /// \brief
+       /// Display the referenced characters.
+       /// Lower depths are obscured by higher depths.
+       void display();
+
+       /// May return NULL.
+       character* get_character_at_depth(int depth);
+
+       /// \brief
+       /// May return NULL.
+       /// If there are multiples, returns the *first* match only!
+       character* get_character_by_name(const tu_string& name);
+
+       /// \brief
+       /// May return NULL.
+       /// If there are multiples, returns the *first* match only!
+       character* get_character_by_name_i(const tu_stringi& name);
+
+       /// \brief 
+       /// Visit each character in the list in depth order
+       /// (lower depth first).
+       //
+       /// The visitor functor will 
+       /// receive a character pointer; must return true if
+       /// it wants next item or false to exit the loop.
+       template <class V>
+       inline void visitForward(V& visitor);
+
+       /// \brief 
+       /// Visit each character in the list in reverse depth
+       /// order (higher depth first).
+       //
+       /// The visitor functor
+       /// will receive a character pointer; must return true if
+       /// it wants next item or false
+       /// to exit the loop.
+       template <class V>
+       inline void visitBackward(V& visitor);
+
+private:
+
+       typedef std::list<DisplayItem> container_type;
+       typedef container_type::iterator iterator;
+       typedef container_type::reverse_iterator reverse_iterator;
+
+       container_type _characters;
+
+       /// dump list to given output stream (debugging)
+       void dump(std::ostream& os);
+
+};
+
+template <class V>
+void
+DisplayList::visitForward(V& visitor)
+{
+       for (iterator it = _characters.begin(),
+                       itEnd = _characters.end();
+               it != itEnd; ++it)
+       {
+               DisplayItem& di = *it;
+
+               //if ( ! di.get_ptr() ) continue;
+
+               if ( ! visitor(di.get_ptr()) )
                {
-                       return m_display_object_array[idx];
+                       break;
                }
+       }
+}
 
+template <class V>
+void
+DisplayList::visitBackward(V& visitor)
+{
+       for (reverse_iterator it = _characters.rbegin(),
+                       itEnd = _characters.rend();
+               it != itEnd; ++it)
+       {
+               DisplayItem& di = *it;
 
-//             void    set_character_position(character* ch, float x, float y);
+               //if ( ! di.get_ptr() ) continue;
 
-       private:
-               std::vector<display_object_info> m_display_object_array;
-       };
+               if ( ! visitor(di.get_ptr()) )
+               {
+                       break;
+               }
+       }
+}
 
 
 }
Index: gnash/server/sprite_instance.cpp
diff -u gnash/server/sprite_instance.cpp:1.6 
gnash/server/sprite_instance.cpp:1.7
--- gnash/server/sprite_instance.cpp:1.6        Sat May 20 23:49:33 2006
+++ gnash/server/sprite_instance.cpp    Mon May 29 12:49:34 2006
@@ -314,6 +314,38 @@
 }
 
 
+struct HeightFinder {
+       float _h;
+       HeightFinder(): _h(0) {}
+       bool operator() (character* ch)
+       {
+               float ch_h = ch->get_height();
+               if (ch_h > _h) {
+                       _h = ch_h;
+               }
+               return true; // keep scanning
+       }
+       float getHeight() {
+               return _h;
+       }
+};
+
+struct WidthFinder {
+       float _w;
+       WidthFinder(): _w(0) {}
+       bool operator() (character* ch) 
+       {
+               float ch_w = ch->get_width();
+               if (ch_w > _w) {
+                       _w = ch_w;
+               }
+               return true; // keep scanning
+       }
+       float getWidth() {
+               return _w;
+       }
+};
+
 //------------------------------------------------
 // sprite_instance
 //------------------------------------------------
@@ -733,7 +765,7 @@
                newname.c_str(),
                dummy_event_handlers,
                depth,
-               true,   // replace if depth is occupied
+               true, // replace if depth is occupied (to drop)
                ch->get_cxform(),
                ch->get_matrix(),
                ch->get_ratio(),
@@ -743,6 +775,7 @@
        }
 }
 
+#if 0
 void sprite_instance::remove_display_object(const tu_string& name)
 {
 //         GNASH_REPORT_FUNCTION;
@@ -754,6 +787,7 @@
            remove_display_object(ch->get_depth(), ch->get_id());
        }
 }
+#endif
 
 bool sprite_instance::on_event(event_id id)
 {
@@ -819,9 +853,9 @@
 void sprite_instance::set_member(const tu_stringi& name,
                const as_value& val)
 {
-           as_standard_member  std_member = get_standard_member(name);
-           switch (std_member)
-               {
+       as_standard_member      std_member = get_standard_member(name);
+       switch (std_member)
+       {
                default:
                case M_INVALID_MEMBER:
                    break;
@@ -962,15 +996,26 @@
 //                             val->set(0.0);
                    return;
                }
-               }       // end switch
+       }       // end switch
 
-                       // 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
+       // 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)
-               {
+       if (text_val)
+       {
+                       // CASE INSENSITIVE compare. 
+                       // In ActionScript 2.0, this must change
+                       // to CASE SENSITIVE!!!
+                       character* ch = m_display_list.get_character_by_name_i( 
name);
+                       if ( ch ) // item found
+                       {
+                               const char* text = val.to_string();
+                               ch->set_text_value(text);
+                               return;
+                       }
+#if 0 // avoid use of DisplayList method taking indexes (moved to private)
                    bool        success = false;
                    for (int i = 0, n = m_display_list.get_character_count(); i 
< n; i++)
                        {
@@ -985,10 +1030,11 @@
                                }
                        }
                    if (success) return;
-               }
+#endif // 0
+       }
 
-           // If that didn't work, set a variable within this environment.
-           m_as_environment.set_member(name, val);
+       // If that didn't work, set a variable within this environment.
+       m_as_environment.set_member(name, val);
 }
 
 const char* sprite_instance::get_variable(const char* path_to_var) const
@@ -1059,7 +1105,7 @@
 
 void sprite_instance::advance(float delta_time)
 {
-//         GNASH_REPORT_FUNCTION;
+       GNASH_REPORT_FUNCTION;
 
 // Keep this (particularly m_as_environment) alive during execution!
        smart_ptr<as_object>    this_ptr(this);
@@ -1079,28 +1125,34 @@
        // Check for the end of frame
        if (m_time_remainder >= frame_time)
        {
-                   m_time_remainder -= frame_time;
+               m_time_remainder -= frame_time;
 
-                   // Update current and next frames.
-                   if (m_play_state == PLAY)
+               // Update current and next frames.
+               if (m_play_state == PLAY)
+               {
+                       int frame_count = m_def->get_frame_count();
+                       if ( m_current_frame == frame_count && frame_count > 1 )
                        {
-                           int current_frame0 = m_current_frame;
-                           increment_frame_and_check_for_loop();
+                               m_display_list.reset();
+                       }
 
-                           // Execute the current frame's tags.
-                           if (m_current_frame != current_frame0)
-                               {
-                                   execute_frame_tags(m_current_frame);
-                               }
+                       int current_frame0 = m_current_frame;
+                       increment_frame_and_check_for_loop();
+
+                       // Execute the current frame's tags.
+                       if (m_current_frame != current_frame0)
+                       {
+                               execute_frame_tags(m_current_frame);
                        }
+               }
 
-                   // Dispatch onEnterFrame event.
-                   on_event(event_id::ENTER_FRAME);
+               // Dispatch onEnterFrame event.
+               on_event(event_id::ENTER_FRAME);
 
-                   do_actions();
+               do_actions();
 
-                   // Clean up display list (remove dead objects).
-                   m_display_list.update();
+               //we don't have the concept of a DisplayList update anymore
+               //m_display_list.update();
        }
 
        // Skip excess time.  TODO root caller should
@@ -1111,9 +1163,11 @@
        m_time_remainder = fmod(m_time_remainder, frame_time);
 }
 
+/* virtual public, reimplemented from gnash::movie */
 void sprite_instance::execute_frame_tags(int frame,
        bool state_only)
 {
+
     // Keep this (particularly m_as_environment) alive during execution!
     smart_ptr<as_object>       this_ptr(this);
 
@@ -1223,7 +1277,8 @@
                        }
 
                    execute_frame_tags(target_frame_number, false);
-                   m_display_list.update();
+                   //we don't have the concept of a DisplayList update anymore
+                   //m_display_list.update();
                }
            else if (target_frame_number > m_current_frame)
                {
@@ -1233,7 +1288,8 @@
                        }
 
                    execute_frame_tags(target_frame_number, false);
-                   m_display_list.update();
+                   //we don't have the concept of a DisplayList update anymore
+                   //m_display_list.update();
                }
 
            m_current_frame = target_frame_number;      
@@ -1273,14 +1329,16 @@
 }
 
 character*
-sprite_instance::add_display_object(uint16_t character_id,
+sprite_instance::add_display_object(
+               uint16_t character_id,
                const char* name,
                const std::vector<swf_event*>& event_handlers,
-               uint16_t depth, bool replace_if_depth_is_occupied,
+               uint16_t depth, 
+               bool replace_if_depth_is_occupied,
                const cxform& color_transform, const matrix& matrix,
                float ratio, uint16_t clip_depth)
 {
-//         GNASH_REPORT_FUNCTION;
+           GNASH_REPORT_FUNCTION;
            assert(m_def != NULL);
 
            character_def*      cdef = m_def->get_character_def(character_id);
@@ -1306,8 +1364,9 @@
            //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:
 
            assert(cdef);
-           smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-           assert(ch != NULL);
+           smart_ptr<character> ch = cdef->create_character_instance(this,
+                       character_id);
+           assert(ch.get_ptr() != NULL);
            if (name != NULL && name[0] != 0)
                {
                    ch->set_name(name);
@@ -1319,10 +1378,9 @@
                    event_handlers[i]->attach_to(ch.get_ptr());
                }}
 
-           m_display_list.add_display_object(
+           m_display_list.place_character(
                ch.get_ptr(),
                depth,
-               replace_if_depth_is_occupied,
                color_transform,
                matrix,
                ratio,
@@ -1344,34 +1402,26 @@
                float ratio,
                uint16_t clip_depth)
 {
-           assert(m_def != NULL);
-           // printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
character_id); // FIXME: debugging crap
-
-           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);
+       assert(m_def != NULL);
+       // printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
character_id); // FIXME: debugging crap
 
-           smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-           assert(ch != NULL);
+       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);
 
-           if (name != NULL && name[0] != 0)
-               {
-                   ch->set_name(name);
-               }
+       smart_ptr<character> ch = cdef->create_character_instance(this,
+                       character_id);
 
-           m_display_list.replace_display_object(
-               ch.get_ptr(),
-               depth,
-               use_cxform,
-               color_transform,
-               use_matrix,
-               mat,
-               ratio,
-               clip_depth);
+       replace_display_object(
+               ch.get_ptr(), name, depth,
+               use_cxform, color_transform,
+               use_matrix, mat,
+               ratio, clip_depth);
 }
 
 void sprite_instance::replace_display_object(
@@ -1385,7 +1435,7 @@
                float ratio,
                uint16_t clip_depth)
 {
-    printf("%s: character %s, id is %d\n", __FUNCTION__, name, ch->get_id()); 
// FIXME:
+    //printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
ch->get_id()); // FIXME:
 
     assert(ch != NULL);
 
@@ -1394,7 +1444,7 @@
            ch->set_name(name);
        }
 
-    m_display_list.replace_display_object(
+    m_display_list.replace_character(
        ch,
        depth,
        use_cxform,
@@ -1407,44 +1457,102 @@
 
 int sprite_instance::get_id_at_depth(int depth)
 {
+#if 0 // don't mess with DisplayList indexes
     int        index = m_display_list.get_display_index(depth);
     if (index == -1) return -1;
 
     character* ch = 
m_display_list.get_display_object(index).m_character.get_ptr();
-
-    return ch->get_id();
+#endif
+    character* ch = m_display_list.get_character_at_depth(depth);
+    if ( ! ch ) return -1;
+    else return ch->get_id();
 }
 
 void sprite_instance::increment_frame_and_check_for_loop()
 {
-    m_current_frame++;
+       //GNASH_REPORT_FUNCTION;
 
-    int        frame_count = m_def->get_frame_count();
-    if (m_current_frame >= frame_count)
+       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)
+               // Loop.
+               m_current_frame = 0;
+               m_has_looped = true;
+               if (frame_count > 1)
                {
-                   m_display_list.reset();
+                       //m_display_list.reset();
                }
        }
+
+       //log_msg("Frame %d/%d", m_current_frame, frame_count);
 }
 
+/// Find a character hit by the given coordinates.
+class MouseEntityFinder {
+
+       movie* _m;
+
+       float _x;
+
+       float _y;
+
+public:
+
+       MouseEntityFinder(float x, float y)
+               :
+               _m(NULL),
+               _x(x),
+               _y(y)
+       {}
+
+       bool operator() (character* ch)
+       {
+               if ( ! ch->get_visible() ) return true;
+
+               movie* te = ch->get_topmost_mouse_entity(_x, _y);
+               if ( te )
+               {
+                       _m = te;
+                       return false; // done
+               }
+
+               return true; // haven't found it yet
+       }
+
+       movie* getEntity() { return _m; }
+               
+};
+
 movie*
 sprite_instance::get_topmost_mouse_entity(float x, float y)
 {
-    if (get_visible() == false) {
-       return NULL;
-    }
+       //GNASH_REPORT_FUNCTION;
 
-    matrix     m = get_matrix();
-    point      p;
-    m.transform_by_inverse(&p, point(x, y));
+       if (get_visible() == false)
+       {
+               return NULL;
+       }
+
+       matrix  m = get_matrix();
+       point   p;
+       m.transform_by_inverse(&p, point(x, y));
+
+       MouseEntityFinder finder(p.m_x, p.m_y);
+       m_display_list.visitBackward(finder);
+       movie* ch = finder.getEntity();
+
+       if ( ch && can_handle_mouse_event() )
+       {
+               return this;
+       }
+       else
+       {
+               return ch; // might be NULL
+       }
 
+#if 0 // rewritten to use the visitor pattern
     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);
@@ -1466,6 +1574,9 @@
        }
 
     return NULL;
+
+#endif // 0
+
 }
 
 bool
@@ -1519,12 +1630,18 @@
     m_play_state = PLAY;
 
     execute_frame_tags(m_current_frame);
-    m_display_list.update();
+    //we don't have the concept of a DisplayList update anymore
+    //m_display_list.update();
 }
 
-float sprite_instance::get_height()
+float sprite_instance::get_height() 
 {
-    float      h = 0; 
+       HeightFinder f;
+       m_display_list.visitForward(f);
+       return f.getHeight(); 
+
+#if 0 // rewritten to use the visitor pattern
+
     int i, n = m_display_list.get_character_count();
     character* ch;
     for (i=0; i < n; i++)
@@ -1540,11 +1657,17 @@
                }
        }
     return h;
+
+#endif // 0
 }
 
-float sprite_instance::get_width()
+float sprite_instance::get_width() 
 {
-    float      w = 0;
+       WidthFinder f;
+       m_display_list.visitForward(f);
+       return f.getWidth(); 
+
+#if 0 // rewritten to use visitor pattern
     int i, n = m_display_list.get_character_count();
     character* ch;
     for (i = 0; i < n; i++)
@@ -1561,6 +1684,7 @@
        }
 
     return w;
+#endif
 }
 
 void sprite_instance::do_something(void *timer)
Index: gnash/server/sprite_instance.h
diff -u gnash/server/sprite_instance.h:1.4 gnash/server/sprite_instance.h:1.5
--- gnash/server/sprite_instance.h:1.4  Sat May 20 23:49:33 2006
+++ gnash/server/sprite_instance.h      Mon May 29 12:49:34 2006
@@ -49,7 +49,7 @@
 
 #include "movie_definition.h"
 #include "movie_root.h"
-#include "dlist.h" // display_list 
+#include "dlist.h" // DisplayList 
 #include "stream.h"
 #include "log.h"
 #include "as_environment.h" // for composition
@@ -112,7 +112,7 @@
 
        float get_width();
 
-       float   get_height();
+       float get_height();
 
        int get_current_frame() const
        {
@@ -182,14 +182,12 @@
        /// Return true if we have any mouse event handlers.
        bool can_handle_mouse_event();
 
+       /// \brief
        /// Return the topmost entity that the given point
        /// covers that can receive mouse events.  NULL if
        /// none.  Coords are in parent's frame.
        virtual movie*  get_topmost_mouse_entity(float x, float y);
 
-       /// Increment m_current_frame, and take care of looping.
-       void    increment_frame_and_check_for_loop();
-
        virtual void    advance(float delta_time);
 
        /// Execute the tags associated with the specified frame.
@@ -236,8 +234,12 @@
        /// Display (render?) this Sprite/MovieClip, unless invisible
        void    display();
 
-       /// Add an object to the DisplayList.
-       character*      add_display_object(
+       /// Add an object to the DisplayList. 
+       //
+       /// @param replace_if_dept_is_occupied
+       ///     unused, always true
+       ///       
+       character* add_display_object(
                uint16_t character_id,
                const char* name,
                const std::vector<swf_event*>& event_handlers,
@@ -288,12 +290,15 @@
                        uint16_t clip_depth);
 
 
+       /// \brief
        /// Remove the object at the specified depth.
-       /// If id != -1, then only remove the object
-       /// at depth with matching id.
+       //
+       /// NOTE: the id parameter is unused, but currently
+       /// required to avoid break of inheritance from movie.h
+       ///
        void    remove_display_object(uint16_t depth, int id)
        {
-           m_display_list.remove_display_object(depth, id);
+           m_display_list.remove_display_object(depth);
        }
 
 
@@ -393,7 +398,10 @@
                const tu_string& newname, uint16_t depth);
 
        /// Remove the object with the specified name.
-       void remove_display_object(const tu_string& name);
+       //
+       /// @@ what happens if the we have multiple objects
+       ///    with the same name ?
+       //void remove_display_object(const tu_string& name);
 
        /// Dispatch event handler(s), if any.
        virtual bool    on_event(event_id id);
@@ -474,7 +482,7 @@
        smart_ptr<movie_definition>     m_def;
        movie_root*     m_root;
 
-       display_list    m_display_list;
+       DisplayList     m_display_list;
 
        //std::vector<action_buffer*>   m_action_list;
        std::vector<action_buffer*>     m_action_list;
@@ -498,6 +506,9 @@
        static as_object as_builtins;
        static void init_builtins();
 
+       /// Increment m_current_frame, and take care of looping.
+       void increment_frame_and_check_for_loop();
+
 };
 
 




reply via email to

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