[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog server/character.cpp server/cha...
From: |
Sandro Santilli |
Subject: |
[Gnash-commit] gnash ChangeLog server/character.cpp server/cha... |
Date: |
Sat, 01 Sep 2007 01:20:47 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Sandro Santilli <strk> 07/09/01 01:20:47
Modified files:
. : ChangeLog
server : character.cpp character.h dlist.cpp dlist.h
movie_root.cpp movie_root.h sprite_instance.cpp
sprite_instance.h
testsuite/actionscript.all: MovieClip.as
testsuite/misc-ming.all: loop_test7.c loop_test8.c
unload_movieclip_test1.c
testsuite/misc-swfc.all: movieclip_destruction_test2.sc
testsuite/swfdec: PASSING
Log message:
* server/dlist.{cpp,h}: when unloaded character's unload()
method
returns true (character or any of its childs has onUnload
methods to
be run) don't really remove it from the list, but just shift
it
down to the "removed" zone. Advance and display only
non-removed
characters (depth-zone based for now, possibly too weak).
Add lots of paranoid invariant testing (not enough, missing
the
one for no unloaded characters out of "removed" depth zone).
* server/character.{cpp,h}: more info about removedDepthOffset,
assertion preveing double unload of a character (this can be
probably easily broken by a focused testcase using
removeMovieClip
on a removed but still-reachable character).
* server/movie_root.{cpp,h}: added cleanupDisplayList() method,
and
call it at the end of actions execution to properly cleanup
removed
but still-reachable characters.
* server/sprite_instance.{cpp,h}: implement a
cleanupDisplayList, to
be called by movie_root, make sure to not include unloaded
characters when visiting the DisplayList for bounds
extractions and
similar.
* testsuite/actionscript.all/MovieClip.as: soft-references
successes
* testsuite/misc-ming.all/: loop_test7.c, loop_test8.c:
keep-alive-for-onUnload successes
* testsuite/misc-ming.all/unload_movieclip_test1.c: successes
* testsuite/misc-swfc.all/movieclip_destruction_test2.sc:
successes
* testsuite/swfdec/PASSING: remove-depths-*.swf successes
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.4179&r2=1.4180
http://cvs.savannah.gnu.org/viewcvs/gnash/server/character.cpp?cvsroot=gnash&r1=1.50&r2=1.51
http://cvs.savannah.gnu.org/viewcvs/gnash/server/character.h?cvsroot=gnash&r1=1.91&r2=1.92
http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.cpp?cvsroot=gnash&r1=1.80&r2=1.81
http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.h?cvsroot=gnash&r1=1.47&r2=1.48
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.cpp?cvsroot=gnash&r1=1.82&r2=1.83
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.h?cvsroot=gnash&r1=1.70&r2=1.71
http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.cpp?cvsroot=gnash&r1=1.319&r2=1.320
http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.h?cvsroot=gnash&r1=1.134&r2=1.135
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/MovieClip.as?cvsroot=gnash&r1=1.87&r2=1.88
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/loop_test7.c?cvsroot=gnash&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/loop_test8.c?cvsroot=gnash&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/unload_movieclip_test1.c?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-swfc.all/movieclip_destruction_test2.sc?cvsroot=gnash&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/swfdec/PASSING?cvsroot=gnash&r1=1.27&r2=1.28
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.4179
retrieving revision 1.4180
diff -u -b -r1.4179 -r1.4180
--- ChangeLog 31 Aug 2007 22:16:49 -0000 1.4179
+++ ChangeLog 1 Sep 2007 01:20:45 -0000 1.4180
@@ -1,3 +1,30 @@
+2007-09-01 Sandro Santilli <address@hidden>
+
+ * server/dlist.{cpp,h}: when unloaded character's unload() method
+ returns true (character or any of its childs has onUnload methods to
+ be run) don't really remove it from the list, but just shift it
+ down to the "removed" zone. Advance and display only non-removed
+ characters (depth-zone based for now, possibly too weak).
+ Add lots of paranoid invariant testing (not enough, missing the
+ one for no unloaded characters out of "removed" depth zone).
+ * server/character.{cpp,h}: more info about removedDepthOffset,
+ assertion preveing double unload of a character (this can be
+ probably easily broken by a focused testcase using removeMovieClip
+ on a removed but still-reachable character).
+ * server/movie_root.{cpp,h}: added cleanupDisplayList() method, and
+ call it at the end of actions execution to properly cleanup removed
+ but still-reachable characters.
+ * server/sprite_instance.{cpp,h}: implement a cleanupDisplayList, to
+ be called by movie_root, make sure to not include unloaded
+ characters when visiting the DisplayList for bounds extractions and
+ similar.
+ * testsuite/actionscript.all/MovieClip.as: soft-references successes
+ * testsuite/misc-ming.all/: loop_test7.c, loop_test8.c:
+ keep-alive-for-onUnload successes
+ * testsuite/misc-ming.all/unload_movieclip_test1.c: successes
+ * testsuite/misc-swfc.all/movieclip_destruction_test2.sc: successes
+ * testsuite/swfdec/PASSING: remove-depths-*.swf successes
+
2007-08-31 Sandro Santilli <address@hidden>
* server/asobj/gen-asclass.sh: add the getObjectInterface call.
Index: server/character.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/character.cpp,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -b -r1.50 -r1.51
--- server/character.cpp 31 Aug 2007 15:40:05 -0000 1.50
+++ server/character.cpp 1 Sep 2007 01:20:46 -0000 1.51
@@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-/* $Id: character.cpp,v 1.50 2007/08/31 15:40:05 strk Exp $ */
+/* $Id: character.cpp,v 1.51 2007/09/01 01:20:46 strk Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -676,8 +676,9 @@
bool
character::unload()
{
- assert(!_unloaded);
+ assert(!_unloaded); // don't unload characters twice !
_unloaded = true;
+
//log_msg(_("Queuing unload event for character %p"), this);
return queueEventHandler(event_id::UNLOAD);
//on_event(event_id::UNLOAD);
Index: server/character.h
===================================================================
RCS file: /sources/gnash/gnash/server/character.h,v
retrieving revision 1.91
retrieving revision 1.92
diff -u -b -r1.91 -r1.92
--- server/character.h 30 Aug 2007 14:13:07 -0000 1.91
+++ server/character.h 1 Sep 2007 01:20:46 -0000 1.92
@@ -19,7 +19,7 @@
//
//
-/* $Id: character.h,v 1.91 2007/08/30 14:13:07 strk Exp $ */
+/* $Id: character.h,v 1.92 2007/09/01 01:20:46 strk Exp $ */
#ifndef GNASH_CHARACTER_H
#define GNASH_CHARACTER_H
@@ -350,6 +350,13 @@
/// depth -32829 (-32769-60) when unloaded and
/// an onUnload event handler is defined for it.
///
+ /// So, to recap:
+ /// 1: -32769 to -16385 are removed
+ /// 2: -16384 to 0 are statics
+ /// 3: Max depth for a PlaceoObject call is 16384 (which
becomes 0 in the statics)
+ /// (all of the above correct?)
+ ///
+ ///
static const int removedDepthOffset = -32769; // -32769;
/// This value is used for m_clip_depth when the value has no meaning, ie.
Index: server/dlist.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/dlist.cpp,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -b -r1.80 -r1.81
--- server/dlist.cpp 31 Aug 2007 14:49:47 -0000 1.80
+++ server/dlist.cpp 1 Sep 2007 01:20:46 -0000 1.81
@@ -28,6 +28,7 @@
#include <iostream>
#include <algorithm>
#include <stack>
+#include <boost/bind.hpp>
namespace gnash {
@@ -98,6 +99,8 @@
int
DisplayList::getNextHighestDepth() const
{
+ testInvariant();
+
int nexthighestdepth=0;
for (const_iterator it = _characters.begin(),
itEnd = _characters.end();
@@ -118,6 +121,8 @@
character*
DisplayList::get_character_at_depth(int depth)
{
+ testInvariant();
+
//GNASH_REPORT_FUNCTION;
//dump();
@@ -143,6 +148,8 @@
character*
DisplayList::get_character_by_name(const std::string& name)
{
+ testInvariant();
+
container_type::iterator it = find_if(
_characters.begin(),
_characters.end(),
@@ -156,6 +163,8 @@
character*
DisplayList::get_character_by_name_i(const std::string& name)
{
+ testInvariant();
+
container_type::iterator it = find_if(
_characters.begin(),
_characters.end(),
@@ -182,6 +191,7 @@
//dump();
assert(ch);
+ assert(!ch->isUnloaded());
ch->set_invalidated();
ch->set_depth(depth);
ch->set_cxform(color_xform);
@@ -208,16 +218,23 @@
InvalidatedRanges old_ranges;
(*it)->add_invalidated_bounds(old_ranges, true);
- (*it)->unload();
+ boost::intrusive_ptr<character> oldCh = *it;
+ bool hasUnloadEvent = oldCh->unload();
+
// replace existing char
*it = DisplayItem(ch);
+ // reinsert removed character if needed
+ if ( hasUnloadEvent ) reinsertRemovedCharacter(oldCh);
+
// extend invalidated bounds
ch->extend_invalidated_bounds(old_ranges);
}
// Give life to this instance
ch->construct();
+
+ testInvariant();
}
void
@@ -236,17 +253,23 @@
{
*it = DisplayItem(ch);
}
+
+ testInvariant();
}
void
DisplayList::addAll(std::vector<character*>& chars, bool replace)
{
+ testInvariant();
+
for (std::vector<character*>::iterator it=chars.begin(),
itEnd=chars.end();
it != itEnd; ++it)
{
add(*it, replace);
}
+
+ testInvariant();
}
void
@@ -258,7 +281,11 @@
int ratio,
int clip_depth)
{
+ testInvariant();
+
//GNASH_REPORT_FUNCTION;
+ assert(ch);
+ assert(!ch->isUnloaded());
ch->set_invalidated();
ch->set_depth(depth);
@@ -292,7 +319,7 @@
}
else
{
- character* oldch = it->get();
+ boost::intrusive_ptr<character> oldch = *it;
InvalidatedRanges old_ranges;
@@ -312,11 +339,14 @@
oldch->add_invalidated_bounds(old_ranges, true);
// Unload old char
- (*it)->unload();
+ bool hasUnloadEvent = oldch->unload();
// replace existing char
*it = di;
+ // reinsert removed character if needed
+ if ( hasUnloadEvent ) reinsertRemovedCharacter(oldch);
+
// extend invalidated bounds
// WARNING: when a new Button character is added,
// the invalidated bounds computation will likely
@@ -330,6 +360,8 @@
// Give life to this instance
ch->construct();
+
+ testInvariant();
}
@@ -343,6 +375,8 @@
int ratio,
int /* clip_depth */)
{
+ testInvariant();
+
//GNASH_REPORT_FUNCTION;
//IF_VERBOSE_DEBUG(log_msg(_("dl::move(%d)"), depth));
@@ -358,6 +392,12 @@
return;
}
+ if ( ch->isUnloaded() )
+ {
+ log_error("Request to move an unloaded character");
+ assert(!ch->isUnloaded());
+ }
+
// TODO: is sign of depth related to accepting anim moves ?
if (ch->get_accept_anim_moves() == false)
{
@@ -378,6 +418,8 @@
{
ch->set_ratio(ratio);
}
+
+ testInvariant();
}
@@ -387,6 +429,8 @@
{
//GNASH_REPORT_FUNCTION;
+ testInvariant();
+
//log_msg(_("Before removing, list is:"));
//dump();
@@ -394,6 +438,8 @@
container_type::size_type size = _characters.size();
#endif
+ // TODO: would it be legal to call remove_display_object with a depth
+ // in the "removed" zone ?
// TODO: optimize to take by-depth order into account
container_type::iterator it = find_if(
_characters.begin(),
@@ -402,15 +448,25 @@
if ( it != _characters.end() )
{
- (*it)->unload();
+ boost::intrusive_ptr<character> oldCh = *it;
+ bool hasUnloadEvent = oldCh->unload();
+
_characters.erase(it);
+ // reinsert removed character if needed
+ // NOTE: could be optimized if we knew exactly how
+ // to handle the case in which the target depth
+ // (after the shift) is occupied already
+ //
+ if ( hasUnloadEvent ) reinsertRemovedCharacter(oldCh);
}
#ifndef NDEBUG
assert(size >= _characters.size());
#endif
+ testInvariant();
+
//log_msg(_("Done removing, list is:"));
//dump();
}
@@ -419,6 +475,7 @@
void
DisplayList::swapDepths(character* ch1, int newdepth)
{
+ testInvariant();
if ( newdepth < character::staticDepthOffset )
{
@@ -429,8 +486,14 @@
return;
}
- assert(ch1->get_depth() != newdepth);
+ int srcdepth = ch1->get_depth();
+
+ // what if source char is at a lower depth ?
+ assert(srcdepth >= character::staticDepthOffset);
+ assert(srcdepth != newdepth);
+
+ // TODO: optimize this scan by taking ch1 depth into account ?
container_type::iterator it1 = find(_characters.begin(),
_characters.end(), ch1);
// upper bound ...
@@ -448,8 +511,6 @@
{
DisplayItem ch2 = *it2;
- int srcdepth = ch1->get_depth();
-
ch2->set_depth(srcdepth);
// TODO: we're not actually invalidated ourselves, rather our
parent is...
@@ -485,17 +546,14 @@
// See displaylist_depths_test6.swf for more info.
ch1->transformedByScript();
-#ifndef NDEBUG
- // TODO: make this a testInvariant() method for DisplayList
- DisplayList sorted = *this;
- sorted.sort();
- assert(*this == sorted); // check we didn't screw up ordering
-#endif
+ testInvariant();
}
void DisplayList::reset(movie_definition& movieDef, size_t tgtFrame, bool
call_unload)
{
+ testInvariant();
+
//GNASH_REPORT_FUNCTION;
// 1. Find all "timeline depth" for the target frame, querying the
@@ -513,20 +571,24 @@
cout << "Current DisplayList: " << *this << endl;
#endif
-
typedef std::vector<int>::iterator SeekIter;
SeekIter startSeek = save.begin();
SeekIter endSeek = save.end();
- for (iterator it = _characters.begin(), itEnd = _characters.end(); it
!= itEnd; )
+ std::vector<DisplayItem> toReinsert;
+
+ iterator it = beginNonRemoved(_characters);
+ for (iterator itEnd = _characters.end(); it != itEnd; )
{
+ testInvariant();
+
DisplayItem& di = *it;
int di_depth = di->get_depth();
/// We won't scan chars in the dynamic depth zone
- if ( di_depth >= 0 ) return;
+ if ( di_depth >= 0 ) break;
/// Always remove non-timeline instances ?
/// Seems so, at least for duplicateMovieClip
@@ -536,7 +598,13 @@
if ( ! info )
{
// Not to be saved, killing
- if ( call_unload ) di->unload();
+ if ( call_unload )
+ {
+ if ( di->unload() )
+ {
+ toReinsert.push_back(di);
+ }
+ }
it = _characters.erase(it);
continue;
}
@@ -546,6 +614,10 @@
// we need to do this in some corner cases.
if(!di->isActionScriptReferenceable())
{
+ // TODO: no unload() call needed here ? would help GC ?
+ // (I guess there can't be any as_value pointing at this
+ // if it's not ActionScriptReferenceable after all...)
+ //
it = _characters.erase(it);
continue;
}
@@ -555,7 +627,13 @@
if( match == save.end())
{
// Not to be saved, killing
- if ( call_unload ) di->unload();
+ if ( call_unload )
+ {
+ if ( di->unload() )
+ {
+ toReinsert.push_back(di);
+ }
+ }
it = _characters.erase(it);
continue;
}
@@ -570,23 +648,44 @@
++it;
}
-}
+ testInvariant();
+
+ std::for_each(toReinsert.begin(), toReinsert.end(),
+ boost::bind(&DisplayList::reinsertRemovedCharacter, this, _1));
+
+ testInvariant();
+}
void
DisplayList::clear_except(const DisplayList& exclude, bool call_unload)
{
+ //log_debug("clear_except(DislpayList, %d) called", call_unload);
//GNASH_REPORT_FUNCTION;
+ testInvariant();
+ //log_debug("First invariant test worked");
+
+
assert(&exclude != this);
const container_type& keepchars = exclude._characters;
+ std::vector<DisplayItem> toReinsert;
+
+ const_iterator keepStart = beginNonRemoved(keepchars);
+ const_iterator keepEnd = keepchars.end();
+
+ //int called=0;
for (iterator it = _characters.begin(), itEnd = _characters.end(); it
!= itEnd; )
{
+
+ testInvariant(); // TODO: expensive
+ //log_debug("Invariant test in iteration %d worked", called++);
+
DisplayItem& di = *it;
bool is_affected = false;
- for (const_iterator kit = keepchars.begin(), kitEnd =
keepchars.end(); kit != kitEnd; ++kit)
+ for (const_iterator kit = keepStart; kit != keepEnd; ++kit)
{
if ( *kit == di )
{
@@ -597,12 +696,27 @@
if (is_affected == false)
{
- if ( call_unload ) di->unload();
+ if ( call_unload )
+ {
+ if ( di->unload() )
+ {
+ toReinsert.push_back(di);
+ }
+ }
it = _characters.erase(it);
continue;
}
it++;
}
+
+ testInvariant();
+ //log_debug("Invariant test after cleanup worked");
+
+ std::for_each(toReinsert.begin(), toReinsert.end(),
+ boost::bind(&DisplayList::reinsertRemovedCharacter, this, _1));
+
+ testInvariant();
+ //log_debug("Invariant test after reinsertion worked");
}
void
@@ -610,8 +724,12 @@
{
//GNASH_REPORT_FUNCTION;
+ testInvariant();
+
const container_type dropchars = from._characters;
+ std::vector<DisplayItem> toReinsert;
+
for (iterator it = _characters.begin(), itEnd = _characters.end(); it
!= itEnd; )
{
DisplayItem& di = *it;
@@ -628,12 +746,25 @@
if (is_affected)
{
- if ( call_unload ) di->unload();
+ if ( call_unload )
+ {
+ if ( di->unload() )
+ {
+ toReinsert.push_back(di);
+ }
+ }
it = _characters.erase(it);
continue;
}
it++;
}
+
+ testInvariant();
+
+ std::for_each(toReinsert.begin(), toReinsert.end(),
+ boost::bind(&DisplayList::reinsertRemovedCharacter, this, _1));
+
+ testInvariant();
}
void
@@ -642,14 +773,22 @@
{
//GNASH_REPORT_FUNCTION;
+ testInvariant();
+
// container_type::size_type size = _characters.size();
// That there was no crash gnash we iterate through the copy
std::list<DisplayItem> tmp_list = _characters;
- for (iterator it = tmp_list.begin(), itEnd = tmp_list.end();
- it != itEnd; ++it)
+ // We only advance characters which are out of the "removed" zone (or
should we check isUnloaded?)
+ // TODO: remove when copying _character to tmp_list directly ?
+ iterator it = beginNonRemoved(tmp_list);
+ //if ( it != tmp_list.end() ) log_debug("First non-removed char at
depth %d", (*it)->get_depth());
+ //iterator it = tmp_list.begin();
+ for (iterator itEnd = tmp_list.end(); it != itEnd; ++it)
{
+ testInvariant(); // expensive !!
+
// @@@@ TODO FIX: If array changes size due to
// character actions, the iteration may not be
// correct!
@@ -684,9 +823,18 @@
boost::intrusive_ptr<character> ch = *it;
assert(ch!=NULL);
+ if ( ch->isUnloaded() ) // debugging
+ {
+ log_error("character at depth %d is unloaded",
ch->get_depth());
+ abort();
+ }
+ assert(! ch->isUnloaded() ); // we don't advance unloaded chars
+
+
ch->advance(delta_time);
}
+ testInvariant();
}
@@ -695,15 +843,27 @@
void
DisplayList::display()
{
+ testInvariant();
+
//GNASH_REPORT_FUNCTION;
std::stack<int> clipDepthStack;
- for( iterator it = _characters.begin(), endIt = _characters.end();
- it != endIt; ++it)
+ // We only advance characters which are out of the "removed" zone (or
should we check isUnloaded?)
+ iterator it = beginNonRemoved(_characters);
+ //iterator it = _characters.begin();
+ for(iterator endIt = _characters.end(); it != endIt; ++it)
{
character* ch = it->get();
assert(ch);
+ if ( ch->isUnloaded() ) // debugging
+ {
+ log_error("character at depth %d is unloaded", ch->get_depth());
+ abort();
+ }
+ assert(! ch->isUnloaded() ); // we don't advance unloaded chars
+
+
// Check if this charater or any of its parents is a mask.
// Characters act as masks should always be rendered to the
// mask buffer despite their visibility.
@@ -761,26 +921,30 @@
void
DisplayList::dump() const
{
+ //testInvariant();
+
int num=0;
for( const_iterator it = _characters.begin(),
endIt = _characters.end();
it != endIt; ++it)
{
const DisplayItem& dobj = *it;
- log_msg(_("Item %d at depth %d (char id %d, name %s, type %s"),
+ log_msg(_("Item %d at depth %d (char id %d, name %s, type %s)"),
num, dobj->get_depth(), dobj->get_id(),
- dobj->get_name().c_str(), typeid(*dobj).name());
+ dobj->get_name().c_str(), typeName(*dobj).c_str());
num++;
}
}
void
-DisplayList::add_invalidated_bounds(InvalidatedRanges& ranges, bool force) {
+DisplayList::add_invalidated_bounds(InvalidatedRanges& ranges, bool force)
+{
- for( iterator it = _characters.begin(),
- endIt = _characters.end();
- it != endIt; ++it)
+ testInvariant();
+
+ iterator it = beginNonRemoved(_characters);
+ for( iterator endIt = _characters.end(); it != endIt; ++it)
{
DisplayItem& dobj = *it;
#ifndef GNASH_USE_GC
@@ -825,6 +989,69 @@
return os;
}
+void
+DisplayList::reinsertRemovedCharacter(boost::intrusive_ptr<character> ch)
+{
+ assert(ch->isUnloaded());
+
+ // TODO: have this done by character::unload() instead ?
+ int oldDepth = ch->get_depth();
+ int newDepth = character::removedDepthOffset - oldDepth;
+ ch->set_depth(newDepth);
+
+ testInvariant();
+
+ container_type::iterator it = find_if(
+ _characters.begin(), _characters.end(),
+ DepthGreaterOrEqual(newDepth));
+ if ( it == _characters.end() || (*it)->get_depth() != newDepth )
+ {
+ // add the new char
+ _characters.insert(it, DisplayItem(ch));
+ }
+ else
+ {
+ // the character should not be in the displaylist already !
+ assert(it->get() != ch.get());
+
+ log_error("DisplayList::insertCharacter: target depth (%d) is
occupied, and we don't know what we're supposed to do - we'll avoid inserting
the character for now", newDepth);
+ }
+
+ testInvariant();
+}
+
+/*private static*/
+DisplayList::iterator
+DisplayList::beginNonRemoved(container_type& c)
+{
+ return std::find_if(c.begin(), c.end(),
+ DepthGreaterOrEqual(character::removedDepthOffset -
character::staticDepthOffset));
+}
+
+/*private static*/
+DisplayList::const_iterator
+DisplayList::beginNonRemoved(const container_type& c)
+{
+ return std::find_if(c.begin(), c.end(),
DepthGreaterOrEqual(character::removedDepthOffset+1));
+}
+
+void
+DisplayList::removeUnloaded()
+{
+ // TODO: erase from begin() to beginNonRemoved()-1 ?
+ //log_debug("removeUnloaded called (dlist:%p)", (void*)this);
+ testInvariant();
+ //log_debug(" first invTest passed, _characters have %d entries",
_characters.size());
+ //dump();
+ iterator last = std::remove_if(_characters.begin(), _characters.end(),
boost::bind(&character::isUnloaded, _1));
+ _characters.erase(last, _characters.end());
+ //log_debug(" After remove_if, _characters have %d entries - dumping
them", _characters.size());
+ //dump();
+ //log_debug(" Now testing invariant again");
+ testInvariant();
+ //log_debug(" second invTest passed");
+}
+
} // namespace gnash
Index: server/dlist.h
===================================================================
RCS file: /sources/gnash/gnash/server/dlist.h,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -b -r1.47 -r1.48
--- server/dlist.h 30 Aug 2007 21:21:58 -0000 1.47
+++ server/dlist.h 1 Sep 2007 01:20:46 -0000 1.48
@@ -28,6 +28,10 @@
#include <list>
#include <iosfwd>
+#ifndef NDEBUG
+#include "log.h"
+#include <set> // for testInvariant
+#endif
namespace gnash {
class cxform;
@@ -49,6 +53,27 @@
public:
+ void testInvariant() const
+ {
+#ifndef NDEBUG
+ DisplayList sorted = *this;
+ // check no duplicated depths in list
+ std::set<int> depths;
+ for (const_iterator it=_characters.begin(),
itEnd=_characters.end(); it!=itEnd; ++it)
+ {
+ boost::intrusive_ptr<character> ch = *it;
+ int depth = ch->get_depth();
+ if ( ! depths.insert(depth).second )
+ {
+ log_debug("Depth %d is duplicated in
DisplayList %p", depth, (void*)this);
+ abort();
+ }
+ }
+ sorted.sort();
+ assert(*this == sorted); // check we didn't screw up ordering
+#endif
+ }
+
/// Output operator
friend std::ostream& operator<< (std::ostream&, const DisplayList&);
@@ -172,6 +197,17 @@
///
void remove_display_object(int depth);
+ /// Remove all unloaded character from the list
+ //
+ /// Removed characters still in the list are those
+ /// on which onUnload event handlers were defined..
+ ///
+ /// NOTE: we don't call the function recursively in the
+ /// contained elements, as that should not be needed
+ /// (ie: any inned thing will not be accessible anyway)
+ ///
+ void removeUnloaded();
+
/// Clear the display list.
void clear()
{
@@ -194,7 +230,7 @@
/// \brief
/// Clear all characters in this DisplayList except the ones
- /// contained in the given DisplayList
+ /// contained in the given DisplayList and not unloaded
//
/// @param exclude
/// A DisplayList containing character instances to keep.
@@ -298,6 +334,11 @@
/// The visitor functor will
/// receive a character pointer; must return true if
/// it wants next item or false to exit the loop.
+ ///
+ /// NOTE: all elements in the list are visited, even
+ /// the removed ones (unloaded)
+ /// TODO: inspect if worth providing an arg to skip removed
+ ///
template <class V>
inline void visitForward(V& visitor);
@@ -309,6 +350,11 @@
/// will receive a character pointer; must return true if
/// it wants next item or false
/// to exit the loop.
+ ///
+ /// NOTE: all elements in the list are visited, even
+ /// the removed ones (unloaded)
+ /// TODO: inspect if worth providing an arg to skip removed
+ ///
template <class V>
inline void visitBackward(V& visitor);
@@ -320,6 +366,11 @@
///
/// The visitor functor will receive a character pointer,
/// it's return value is not used so can return void.
+ ///
+ /// NOTE: all elements in the list are visited, even
+ /// the removed ones (unloaded)
+ /// TODO: inspect if worth providing an arg to skip removed
+ ///
template <class V>
inline void visitAll(V& visitor);
@@ -379,6 +430,24 @@
typedef container_type::reverse_iterator reverse_iterator;
typedef container_type::const_reverse_iterator const_reverse_iterator;
+ /// Return an iterator to the first element of the container NOT in the
"removed" depth zone
+ static iterator beginNonRemoved(container_type& c);
+
+ /// Return an iterator to the first element of the container NOT in the
"removed" depth zone
+ static const_iterator beginNonRemoved(const container_type& c);
+
+ /// Re-insert a removed-from-stage character after appropriately
+ /// shifting its depth based on the character::removedDepthOffset
+ /// value.
+ //
+ /// PRE-CONDITIONS
+ /// - ch::isUnloaded() returns true (assertion fails otherwise)
+ /// - ch is not already in the list (assertion fails otherwise)
+ ///
+ /// TODO: inspect what should happen if the target depth is already
occupied
+ ///
+ void reinsertRemovedCharacter(boost::intrusive_ptr<character> ch);
+
container_type _characters;
Index: server/movie_root.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/movie_root.cpp,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -b -r1.82 -r1.83
--- server/movie_root.cpp 3 Aug 2007 21:44:32 -0000 1.82
+++ server/movie_root.cpp 1 Sep 2007 01:20:46 -0000 1.83
@@ -670,6 +670,10 @@
#endif
processActionQueue();
+ // Delete characters removed from the stage
+ // from the display lists
+ cleanupDisplayList();
+
#ifdef GNASH_USE_GC
// Run the garbage collector (step back !!)
GC::get().collect();
@@ -1197,6 +1201,18 @@
}
void
+movie_root::cleanupDisplayList()
+{
+ // scan a backup copy of the levels, so that movies advancement won't
+ // invalidate iterators
+ Levels cached = _movies;
+ for (Levels::reverse_iterator i=cached.rbegin(), e=cached.rend(); i!=e;
++i)
+ {
+ i->second->cleanupDisplayList();
+ }
+}
+
+void
movie_root::advanceMovie(boost::intrusive_ptr<sprite_instance> movie, float
delta_time)
{
#ifdef GNASH_DEBUG
Index: server/movie_root.h
===================================================================
RCS file: /sources/gnash/gnash/server/movie_root.h,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -b -r1.70 -r1.71
--- server/movie_root.h 2 Aug 2007 22:07:26 -0000 1.70
+++ server/movie_root.h 1 Sep 2007 01:20:46 -0000 1.71
@@ -15,7 +15,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: movie_root.h,v 1.70 2007/08/02 22:07:26 strk Exp $ */
+/* $Id: movie_root.h,v 1.71 2007/09/01 01:20:46 strk Exp $ */
/// \page events_handling Handling of user events
///
@@ -669,6 +669,10 @@
// Advance all levels
void advanceAllLevels(float delta_time);
+ /// Delete characters removed from the stage
+ /// from the display lists
+ void cleanupDisplayList();
+
// Advance a given level
void advanceMovie(boost::intrusive_ptr<sprite_instance> movie, float
delta_time);
Index: server/sprite_instance.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/sprite_instance.cpp,v
retrieving revision 1.319
retrieving revision 1.320
diff -u -b -r1.319 -r1.320
--- server/sprite_instance.cpp 31 Aug 2007 21:53:31 -0000 1.319
+++ server/sprite_instance.cpp 1 Sep 2007 01:20:46 -0000 1.320
@@ -1630,6 +1630,8 @@
{}
void operator() (character* ch)
{
+ // don't include bounds of unloaded characters
+ if ( ch->isUnloaded() ) return;
geometry::Range2d<float> chb = ch->getBounds();
matrix m = ch->get_matrix();
m.transform(chb);
@@ -1655,6 +1657,9 @@
void operator() (character* ch)
{
+ // don't include bounds of unloaded characters
+ if ( ch->isUnloaded() ) return;
+
// TODO: Are script-transformed object to be kept ?
// Need a testcase for this
//if ( ! ch->get_accept_anim_moves() )
@@ -1681,10 +1686,12 @@
unloadEvents(0)
{}
- bool operator() (character* ch)
+ void operator() (character* ch)
{
+ // don't unload already unloaded characters
+ if ( ch->isUnloaded() ) return;
+
if ( ch->unload() ) ++unloadEvents;
- return true;
}
bool foundUnloadEvents() const
@@ -2325,6 +2332,8 @@
// to need oldDisplayList again later, to extract the list of
// newly added characters
//
+ //oldDisplayList.removeUnloaded(); // TODO: clean oldDisplayList here
instead than in cleanupDisplayList ?
+ oldDisplayList.sort(); // this is to avoid failing assertions, since we
know characters might have changed depth...
DisplayList stillAlive = oldDisplayList;
stillAlive.clear_except(m_display_list, false);
//log_msg(_("Advancing %d pre-existing children of %s"),
stillAlive.size(), getTargetPath().c_str());
@@ -2335,15 +2344,12 @@
//log_msg(_("Executing actions in %s timeline"),
getTargetPath().c_str());
do_actions();
- // Call UNLOAD event of just removed chars !
- //DisplayList justRemoved = oldDisplayList;
- //justRemoved.clear_except(m_display_list, false); // true;
- // No, dont' call UNLOAD event, as it should be called by
remove_display_object!
-
- // Finally, execute actions in newly added childs
+ // Finally, execute actions in (we actually "advance") newly added
+ // (and not unloaded) childs
//
// These are elements in the current DisplayList, cleared
- // by all elements in oldDisplayList.
+ // by all unloaded elements and by non-unloaded elements in
+ // oldDisplayList.
//
// Of course we do NOT call UNLOAD events here, as
// the chars we're clearing have *not* been removed:
@@ -2351,6 +2357,7 @@
//
DisplayList newlyAdded = m_display_list;
//log_msg(_("%s has %d current children and %d old children"),
getTargetPath().c_str(), m_display_list.size(), oldDisplayList.size());
+ newlyAdded.removeUnloaded();
newlyAdded.clear(oldDisplayList, false);
//log_msg(_("Advancing %d newly-added (after clearing) children of
%s"), newlyAdded.size(), getTargetPath().c_str());
newlyAdded.advance(delta_time);
@@ -3372,7 +3379,7 @@
#endif
UnloaderVisitor visitor;
- m_display_list.visitForward(visitor);
+ m_display_list.visitAll(visitor);
return character::unload() || visitor.foundUnloadEvents();
@@ -3628,6 +3635,9 @@
void operator() (character* ch)
{
+ // don't enumerate unloaded characters
+ if ( ch->isUnloaded() ) return;
+
_env.push(ch->get_name());
}
};
@@ -3639,6 +3649,14 @@
m_display_list.visitAll(visitor);
}
+void
+sprite_instance::cleanupDisplayList()
+{
+ //log_debug("%s.cleanDisplayList() called, current dlist is %p, old is
%p", getTarget().c_str(), (void*)&m_display_list, (void*)&oldDisplayList);
+ m_display_list.removeUnloaded();
+ oldDisplayList.removeUnloaded(); // TODO: move unloaded-cleanup of
oldDisplayList in advance_sprite ?
+}
+
#ifdef GNASH_USE_GC
struct ReachableMarker {
void operator() (character *ch)
Index: server/sprite_instance.h
===================================================================
RCS file: /sources/gnash/gnash/server/sprite_instance.h,v
retrieving revision 1.134
retrieving revision 1.135
diff -u -b -r1.134 -r1.135
--- server/sprite_instance.h 31 Aug 2007 07:56:11 -0000 1.134
+++ server/sprite_instance.h 1 Sep 2007 01:20:47 -0000 1.135
@@ -748,6 +748,10 @@
return _origTarget;
}
+ /// Delete characters removed from the stage
+ /// from the display lists
+ void cleanupDisplayList();
+
private:
/// \brief
Index: testsuite/actionscript.all/MovieClip.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/MovieClip.as,v
retrieving revision 1.87
retrieving revision 1.88
diff -u -b -r1.87 -r1.88
--- testsuite/actionscript.all/MovieClip.as 31 Aug 2007 21:53:33 -0000
1.87
+++ testsuite/actionscript.all/MovieClip.as 1 Sep 2007 01:20:47 -0000
1.88
@@ -20,7 +20,7 @@
// compile this test case with Ming makeswf, and then
// execute it like this gnash -1 -r 0 -v out.swf
-rcsid="$Id: MovieClip.as,v 1.87 2007/08/31 21:53:33 strk Exp $";
+rcsid="$Id: MovieClip.as,v 1.88 2007/09/01 01:20:47 strk Exp $";
#include "check.as"
@@ -481,23 +481,23 @@
#endif
check_equals(typeof(hardref), 'undefined');
-xcheck_equals(typeof(hardref2), 'movieclip');
-xcheck_equals(typeof(hardref3), 'movieclip'); // still accessible due to
onUnload defined for its child
-xcheck_equals(hardref2.getDepth(), -32839);
-xcheck_equals(hardref3.getDepth(), -32849);
-xcheck_equals(hardref3.hardref3child.getDepth(), 1);
+check_equals(typeof(hardref2), 'movieclip');
+check_equals(typeof(hardref3), 'movieclip'); // still accessible due to
onUnload defined for its child
+check_equals(hardref2.getDepth(), -32839);
+check_equals(hardref3.getDepth(), -32849);
+check_equals(hardref3.hardref3child.getDepth(), 1);
check_equals(typeof(softref), 'movieclip');
check_equals(typeof(softref2), 'movieclip');
check_equals(typeof(softref3), 'movieclip');
check_equals(typeof(softref3child), 'movieclip');
check_equals(typeof(softref.member), 'undefined');
check_equals(typeof(softref._target), 'undefined');
-xcheck_equals(softref2.member, 2);
-xcheck_equals(softref2._target, '/hardref2');
-xcheck_equals(softref3.member, 3);
-xcheck_equals(softref3._target, '/hardref3');
-xcheck_equals(softref3child.member, '3child');
-xcheck_equals(softref3child._target, '/hardref3/hardref3child');
+check_equals(softref2.member, 2);
+check_equals(softref2._target, '/hardref2');
+check_equals(softref3.member, 3);
+check_equals(softref3._target, '/hardref3');
+check_equals(softref3child.member, '3child');
+check_equals(softref3child._target, '/hardref3/hardref3child');
hardref = 4;
// Delete is needed, or further inspection functions will hit the variable
before the character
delete hardref;
Index: testsuite/misc-ming.all/loop_test7.c
===================================================================
RCS file: /sources/gnash/gnash/testsuite/misc-ming.all/loop_test7.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- testsuite/misc-ming.all/loop_test7.c 1 Jul 2007 10:54:57 -0000
1.5
+++ testsuite/misc-ming.all/loop_test7.c 1 Sep 2007 01:20:47 -0000
1.6
@@ -122,7 +122,7 @@
// RemoveObject2 is *before* the DoAction, then typeof(movieClip1) will
reurn 'undefined'.
// So Gnash fails here because of action execution order!
// TODO: add testcase for this(RemoveObject2 placed *before* DoAction within
the same frame).
- xcheck_equals(mo, "typeof(movieClip1)", "'movieclip'"); // kept alive for
calling onUnload!
+ check_equals(mo, "typeof(movieClip1)", "'movieclip'"); // kept alive for
calling onUnload!
check_equals(mo, "_root.mc1Constructed", "1");
SWFMovie_nextFrame(mo);
@@ -133,7 +133,7 @@
check_equals(mo, "typeof(movieClip1)", "'undefined'");
SWFMovie_add(mo, (SWFBlock)newSWFAction( "gotoAndStop(4);"));
- xcheck_equals(mo, "typeof(movieClip1)", "'movieclip'");
+ check_equals(mo, "typeof(movieClip1)", "'movieclip'");
// onConstruct is called twice
check_equals(mo, "_root.mc1Constructed", "2");
Index: testsuite/misc-ming.all/loop_test8.c
===================================================================
RCS file: /sources/gnash/gnash/testsuite/misc-ming.all/loop_test8.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- testsuite/misc-ming.all/loop_test8.c 1 Jul 2007 10:54:57 -0000
1.6
+++ testsuite/misc-ming.all/loop_test8.c 1 Sep 2007 01:20:47 -0000
1.7
@@ -221,7 +221,7 @@
check_equals(mo, "typeof(mc2)", "'undefined'");
check_equals(mo, "typeof(mc3)", "'movieclip'");
check_equals(mo, "typeof(mc4)", "'movieclip'");
- xcheck_equals(mo, "typeof(mc5)", "'movieclip'"); // Gnash fails because of
action execution order
+ check_equals(mo, "typeof(mc5)", "'movieclip'"); // Gnash fails because of
action execution order
check_equals(mo, "mc1Constructed", "1");
check_equals(mo, "mc2Constructed", "1");
check_equals(mo, "mc3Constructed", "2");
Index: testsuite/misc-ming.all/unload_movieclip_test1.c
===================================================================
RCS file:
/sources/gnash/gnash/testsuite/misc-ming.all/unload_movieclip_test1.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- testsuite/misc-ming.all/unload_movieclip_test1.c 20 Jul 2007 02:02:08
-0000 1.3
+++ testsuite/misc-ming.all/unload_movieclip_test1.c 1 Sep 2007 01:20:47
-0000 1.4
@@ -88,7 +88,7 @@
add_actions(mo, "mc.onUnload = function () { "
" _root.x = this._currentframe; "
" _root.check_equals(typeof(this), 'movieclip'); "
- " _root.xcheck_equals(this, _root.mc); "
+ " _root.check_equals(this, _root.mc); "
"};");
SWFMovie_nextFrame(mo);
@@ -99,7 +99,7 @@
// Frame 4: checks
- xcheck_equals(mo, "_root.x", "1");
+ check_equals(mo, "_root.x", "1");
add_actions(mo, "_root.totals(); stop(); ");
SWFMovie_nextFrame(mo);
Index: testsuite/misc-swfc.all/movieclip_destruction_test2.sc
===================================================================
RCS file:
/sources/gnash/gnash/testsuite/misc-swfc.all/movieclip_destruction_test2.sc,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- testsuite/misc-swfc.all/movieclip_destruction_test2.sc 31 Aug 2007
14:49:48 -0000 1.5
+++ testsuite/misc-swfc.all/movieclip_destruction_test2.sc 1 Sep 2007
01:20:47 -0000 1.6
@@ -87,12 +87,12 @@
{
_root.mc2UnlaodedCount++;
// mc2.testvar keeps alive as long as mc2 is alive
- _root.xcheck_equals(mc2.testvar, 100);
+ _root.check_equals(mc2.testvar, 100);
};
mc3.onUnload = function ()
{
_root.mc3UnlaodedCount++;
- _root.xcheck_equals(mc3.testvar, 100);
+ _root.check_equals(mc3.testvar, 100);
};
mc2.testvar = 100;
@@ -114,38 +114,38 @@
xcheck_equals(mc2UnlaodedCount, 1); //mc2.onUnload triggered
xcheck_equals(mc2UnlaodedCount, 1); //mc3.onUnload triggered
check_equals(mc1Ref.valueOf(), null);
- xcheck_equals(mc2Ref, mc2);
- xcheck_equals(mc3Ref, mc3);
+ check_equals(mc2Ref, mc2);
+ check_equals(mc3Ref, mc3);
check_equals(typeof(mc1), 'undefined'); //cann't access the hard reference
- xcheck_equals(typeof(mc2), 'movieclip'); // mc2 is still accessable
- xcheck_equals(typeof(mc3), 'movieclip'); // mc3 is still accessable
- xcheck_equals(mc2.getDepth(), -16387); // depth of mc2 changed after
onUnload
- xcheck_equals(mc3.getDepth(), -16388); // depth of mc3 changed after
onUnload
+ check_equals(typeof(mc2), 'movieclip'); // mc2 is still accessable
+ check_equals(typeof(mc3), 'movieclip'); // mc3 is still accessable
+ check_equals(mc2.getDepth(), -16387); // depth of mc2 changed after
onUnload
+ check_equals(mc3.getDepth(), -16388); // depth of mc3 changed after
onUnload
mc2.swapDepths(mc3);
- xcheck_equals(mc2.getDepth(), -16387); // depth not change after
swapDepths
- xcheck_equals(mc3.getDepth(), -16388); // depth not change after
swapDepths
+ check_equals(mc2.getDepth(), -16387); // depth not change after swapDepths
+ check_equals(mc3.getDepth(), -16388); // depth not change after swapDepths
mc2.swapDephts(-10);
mc2.swapDephts(10);
- xcheck_equals(mc2.getDepth(), -16387); // depth not change after
swapDepths
- xcheck_equals(mc3.getDepth(), -16388); // depth not change after
swapDepths
+ check_equals(mc2.getDepth(), -16387); // depth not change after swapDepths
+ check_equals(mc3.getDepth(), -16388); // depth not change after swapDepths
- xcheck_equals(mc2.testvar, 100);
- xcheck_equals(mc3.testvar, 100);
+ check_equals(mc2.testvar, 100);
+ check_equals(mc3.testvar, 100);
mc2.removMovieClip();
mc3.removMovieClip();
xcheck_equals(mc2UnlaodedCount, 1); //mc2.onUnload not triggered again
xcheck_equals(mc2UnlaodedCount, 1); //mc3.onUnload not triggered again
- xcheck_equals(typeof(mc2), 'movieclip'); // mc2 is still accessible
- xcheck_equals(typeof(mc3), 'movieclip'); // mc3 is still accessible
- xcheck_equals(mc2.getDepth(), -16387);
- xcheck_equals(mc3.getDepth(), -16388);
- xcheck_equals(mc2._x, 200);
- xcheck_equals(mc3._y, 300);
- xcheck_equals(mc2.testvar, 100);
- xcheck_equals(mc3.testvar, 100);
+ check_equals(typeof(mc2), 'movieclip'); // mc2 is still accessible
+ check_equals(typeof(mc3), 'movieclip'); // mc3 is still accessible
+ check_equals(mc2.getDepth(), -16387);
+ check_equals(mc3.getDepth(), -16388);
+ check_equals(mc2._x, 200);
+ check_equals(mc3._y, 300);
+ check_equals(mc2.testvar, 100);
+ check_equals(mc3.testvar, 100);
mc2.onUnload();
mc3.onUnload();
Index: testsuite/swfdec/PASSING
===================================================================
RCS file: /sources/gnash/gnash/testsuite/swfdec/PASSING,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -b -r1.27 -r1.28
--- testsuite/swfdec/PASSING 31 Aug 2007 21:53:33 -0000 1.27
+++ testsuite/swfdec/PASSING 1 Sep 2007 01:20:47 -0000 1.28
@@ -193,3 +193,6 @@
with-outobject-6.swf
with-outobject-7.swf
with-outobject-8.swf
+remove-depths-6.swf
+remove-depths-7.swf
+remove-depths-8.swf