gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11615: Centralize movie loading wit


From: Sandro Santilli
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11615: Centralize movie loading with the movie_root service.
Date: Tue, 10 Nov 2009 02:00:48 +0100
User-agent: Bazaar (1.16.1)

------------------------------------------------------------
revno: 11615 [merge]
committer: Sandro Santilli <address@hidden>
branch nick: trunk
timestamp: Tue 2009-11-10 02:00:48 +0100
message:
  Centralize movie loading with the movie_root service.
  Should now be easier to work on the async load.
modified:
  libcore/DisplayObject.cpp
  libcore/DisplayObject.h
  libcore/MovieClip.cpp
  libcore/MovieClip.h
  libcore/asobj/MovieClipLoader.cpp
  libcore/asobj/flash/display/MovieClip_as.cpp
  libcore/movie_root.cpp
  libcore/movie_root.h
  libcore/vm/ExecutableCode.h
  testsuite/swfdec/PASSING
=== modified file 'libcore/DisplayObject.cpp'
--- a/libcore/DisplayObject.cpp 2009-11-06 09:07:36 +0000
+++ b/libcore/DisplayObject.cpp 2009-11-09 23:07:58 +0000
@@ -113,6 +113,19 @@
     return _object;
 }
 
+void
+DisplayObject::getLoadedMovie(Movie* extern_movie)
+{
+    LOG_ONCE(
+    log_unimpl("loadMovie against a %s DisplayObject", typeName(*this))
+    );
+
+    // TODO: look at the MovieClip implementation, but most importantly
+    //       test all the event handlers copies etc..
+
+    UNUSED(extern_movie);
+}
+
 std::string
 DisplayObject::getNextUnnamedInstanceName()
 {

=== modified file 'libcore/DisplayObject.h'
--- a/libcore/DisplayObject.h   2009-11-06 23:18:38 +0000
+++ b/libcore/DisplayObject.h   2009-11-08 13:13:45 +0000
@@ -809,6 +809,9 @@
     ///
     virtual bool unload();
 
+    /// Accept a loaded Movie
+    virtual void getLoadedMovie(Movie* newMovie);
+
     /// Return true if this DisplayObject was unloaded from the stage
     bool unloaded() const { return _unloaded; }
 

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2009-11-06 09:07:36 +0000
+++ b/libcore/MovieClip.cpp     2009-11-09 21:58:54 +0000
@@ -395,10 +395,6 @@
     assert(_swf);
     assert(object);
 
-    if (!isAS3(getVM(*object)) && !get_parent()) {
-        object->init_member("$version", getVM(*object).getPlayerVersion(), 0); 
-    }
-
     _environment.set_target(this);
 
 }
@@ -1921,6 +1917,10 @@
             getTarget());
 #endif
 
+    if (!isAS3(getVM(*getObject(this))) && !get_parent()) {
+        getObject(this)->init_member("$version", 
getVM(*getObject(this)).getPlayerVersion(), 0); 
+    }
+
     bool eventHandlersInvoked = false;
 
     do {
@@ -2031,6 +2031,52 @@
     return shouldKeepAlive;
 }
 
+void
+MovieClip::getLoadedMovie(Movie* extern_movie)
+{
+    DisplayObject* parent = get_parent();
+    if (parent)
+    {
+        extern_movie->set_parent(parent);
+
+        // Copy own lockroot value
+        extern_movie->setLockRoot(getLockRoot());
+
+        // Copy own event handlers
+        // see testsuite/misc-ming.all/loadMovieTest.swf
+        const Events& clipEvs = get_event_handlers();
+        // top-level movies can't have clip events, right ?
+        assert (extern_movie->get_event_handlers().empty());
+        extern_movie->set_event_handlers(clipEvs);
+
+        // Copy own name
+        // TODO: check empty != none...
+        const std::string& name = get_name();
+        if( !name.empty() ) extern_movie->set_name(name);
+
+        // Copy own clip depth (TODO: check this)
+        extern_movie->set_clip_depth(get_clip_depth());
+
+        // Replace ourselves in parent
+        // TODO: don't pretend our parent is a MovieClip,
+        //       could as well be a button I guess...
+        //       At most we should require it to be a
+        //       DisplayObjectContainer and log an error if it's not.
+        MovieClip* parent_sp = parent->to_movie();
+        assert(parent_sp);
+        parent_sp->replace_display_object(extern_movie, get_depth(),
+                     true, true);
+
+    }
+    else
+    {
+        // replaceLevel will set depth for us
+        stage().replaceLevel(get_depth() - DisplayObject::staticDepthOffset,
+                              extern_movie);
+    }
+}
+
+
 
 bool
 MovieClip::loadMovie(const URL& url, const std::string* postdata)

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2009-11-06 08:44:44 +0000
+++ b/libcore/MovieClip.h       2009-11-08 13:13:45 +0000
@@ -474,8 +474,16 @@
     ///  IF not NULL, use as the POST body for HTTP requests
     ///
     /// Return: true if it succeeded, false otherwise
+    ///
+    /// @deprecated use movie_root::loadMovie instead to queue
+    ///             a load and getLoadedMovie to have objects of
+    ///             this class receive a loaded external movie
+    ///     
     bool loadMovie(const URL& url, const std::string* postdata=NULL);
 
+    // See dox in DisplayObject.h
+    virtual void getLoadedMovie(Movie* newMovie);
+
     /// \brief
     /// Load url-encoded variables from the given url, optionally
     /// sending variables from this timeline too.

=== modified file 'libcore/asobj/MovieClipLoader.cpp'
--- a/libcore/asobj/MovieClipLoader.cpp 2009-11-04 13:37:17 +0000
+++ b/libcore/asobj/MovieClipLoader.cpp 2009-11-10 00:59:35 +0000
@@ -58,64 +58,6 @@
     void attachMovieClipLoaderInterface(as_object& o);
 }
 
-/// This class is used to queue a function call action
-//
-/// Exact use is to queue onLoadInit, which should be invoked
-/// after actions of in first frame of a loaded movie are executed.
-/// Since those actions are queued the only way to execute something
-/// after them is to queue the function call as well.
-///
-/// The class might be made more general and accessible outside
-/// of the MovieClipLoader class. For now it only works for
-/// calling a function with a two argument.
-///
-class DelayedFunctionCall : public ExecutableCode
-{
-
-public:
-
-    DelayedFunctionCall(as_object* target, string_table::key name,
-            const as_value& arg1, const as_value& arg2)
-        :
-        _target(target),
-        _name(name),
-        _arg1(arg1),
-        _arg2(arg2)
-    {}
-
-
-    ExecutableCode* clone() const
-    {
-        return new DelayedFunctionCall(*this);
-    }
-
-    virtual void execute()
-    {
-        _target->callMethod(_name, _arg1, _arg2);
-    }
-
-#ifdef GNASH_USE_GC
-    /// Mark reachable resources (for the GC)
-    //
-    /// Reachable resources are:
-    ///  - the action target (_target)
-    ///
-    virtual void markReachableResources() const
-    {
-      _target->setReachable();
-      _arg1.setReachable();
-      _arg2.setReachable();
-    }
-#endif // GNASH_USE_GC
-
-private:
-
-    as_object* _target;
-    string_table::key _name;
-    as_value _arg1, _arg2;
-
-};
-
 void
 registerMovieClipLoaderNative(as_object& global)
 {
@@ -181,11 +123,14 @@
        const std::string& str_url = fn.arg(0).to_string(); 
 
        as_value tgt_arg = fn.arg(1);
-
-       std::string tgt_str = tgt_arg.to_string();
+       const std::string& tgt_str = tgt_arg.to_string();
+
+    movie_root& mr = getRoot(*ptr);
+
+    // TODO: check if this logic can be generic to movie_root::loadMovie
        DisplayObject* target = fn.env().find_target(tgt_str);
-
-       if (!target) {
+    unsigned int junk;
+       if (!target && ! mr.isLevelTarget(tgt_str, junk) ) {
                IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Could not find target %s (evaluated from %s)"),
                        tgt_str, tgt_arg);
@@ -193,72 +138,9 @@
                return as_value(false);
        }
 
-       MovieClip* sprite = target->to_movie();
-       if (!sprite) {
-               IF_VERBOSE_ASCODING_ERRORS(
-               log_aserror(_("Target %s is not a sprite instance (%s)"),
-                       target->getTarget(), typeName(*target));
-               );
-               return as_value(false);
-       }
-
-    as_value targetVal(getObject(sprite));
-
-    movie_root& mr = getRoot(*ptr);
-       URL url(str_url, mr.runResources().baseURL());
-       
-       bool ret = sprite->loadMovie(url);
-       if (!ret) {
-
-        // FIXME: docs suggest the string can be either "URLNotFound" or
-        // "LoadNeverCompleted". This is neither of them:
-               as_value arg1("Failed to load movie or jpeg");
-
-               // FIXME: The last argument is HTTP status, or 0 if no 
connection
-        // was attempted (sandbox) or no status information is available
-        // (supposedly the Adobe mozilla plugin).
-               as_value arg2(0.0);
-               ptr->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadError",
-                getObject(sprite), arg1, arg2);
-
-               return as_value(true);
-       }
-
-    // this is to resolve the soft ref
-       MovieClip* newChar = targetVal.to_sprite(); 
-       if (!newChar) {
-               // We could assert, but let's try to be nicer...
-               log_error("MovieClip::loadMovie destroyed self without 
replacing?");
-               return as_value(true);
-       }
-
-       // Dispatch onLoadStart
-       ptr->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadStart", targetVal);
-
-       // Dispatch onLoadProgress
-       size_t bytesLoaded = newChar->get_bytes_loaded();
-       size_t bytesTotal = newChar->get_bytes_total();
-       ptr->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadProgress", 
targetVal,
-               bytesLoaded, bytesTotal);
-
-       // Dispatch onLoadComplete
-       ptr->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadComplete", 
targetVal,
-               as_value(0.0)); // TODO: find semantic of last arg
-
-       /// This event must be dispatched when actions
-       /// in first frame of loaded clip have been executed.
-       ///
-       /// Since MovieClip::loadMovie above will invoke stagePlacementCallback
-       /// and thus queue all actions in first frame, we'll queue the
-       /// onLoadInit call next, so it happens after the former.
-       std::auto_ptr<ExecutableCode> code(
-            new DelayedFunctionCall(ptr, NSV::PROP_BROADCAST_MESSAGE, 
-                "onLoadInit", targetVal));
-
-       getRoot(*ptr).pushAction(code, movie_root::apDOACTION);
-
-       return as_value(true);
-
+    // TODO: return code is based on target validity if I'm not wrong
+    mr.loadMovie(str_url, tgt_str, "", MovieClip::METHOD_NONE, ptr);
+    return as_value(true);
 }
 
 as_value

=== modified file 'libcore/asobj/flash/display/MovieClip_as.cpp'
--- a/libcore/asobj/flash/display/MovieClip_as.cpp      2009-11-04 16:55:59 
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.cpp      2009-11-09 23:07:58 
+0000
@@ -901,13 +901,13 @@
 as_value
 movieclip_loadMovie(const fn_call& fn)
 {
-    MovieClip* movieclip = ensure<IsDisplayObject<MovieClip> >(fn);
+    DisplayObject* dobj = ensure<IsDisplayObject<> >(fn);
 
     as_value val;
     if (fn.nargs > 1) {
-        val = getObject(movieclip)->callMethod(NSV::PROP_METH, fn.arg(1));
+        val = getObject(dobj)->callMethod(NSV::PROP_METH, fn.arg(1));
     }
-    else val = getObject(movieclip)->callMethod(NSV::PROP_METH);
+    else val = getObject(dobj)->callMethod(NSV::PROP_METH);
 
     if (fn.nargs < 1) // url
     {
@@ -933,7 +933,7 @@
     }
 
     movie_root& mr = getRoot(fn);
-    std::string target = movieclip->getTarget();
+    std::string target = dobj->getTarget();
 
     // TODO: if GET/POST should send variables of *this* movie,
     // no matter if the target will be replaced by another movie !!
@@ -945,7 +945,7 @@
     // This is just an optimization if we aren't going
     // to send the data anyway. It might be wrong, though.
     if (method != MovieClip::METHOD_NONE) {
-        getURLEncodedVars(*getObject(movieclip), data);
+        getURLEncodedVars(*getObject(dobj), data);
     }
  
     mr.loadMovie(urlstr, target, data, method);

=== modified file 'libcore/movie_root.cpp'
--- a/libcore/movie_root.cpp    2009-11-06 07:54:33 +0000
+++ b/libcore/movie_root.cpp    2009-11-10 00:59:35 +0000
@@ -186,10 +186,22 @@
        _intervalTimers.clear();
 }
 
+void
+movie_root::clearLoadMovieRequests()
+{
+    for (LoadMovieRequests::iterator it=_loadMovieRequests.begin(),
+            end = _loadMovieRequests.end(); it != end; ++it)
+    {
+        delete *it;
+    }
+    _loadMovieRequests.clear();
+}
+
 movie_root::~movie_root()
 {
        clearActionQueue();
        clearIntervalTimers();
+       clearLoadMovieRequests();
 
        assert(testInvariant());
 }
@@ -287,7 +299,7 @@
                _movies[movie->get_depth()] = movie; 
        }
        else
-       {
+    {
                // don't leak overloaded levels
 
                LevelMovie lm = it->second;
@@ -479,6 +491,21 @@
        return true;
 }
 
+void
+movie_root::replaceLevel(unsigned int num, Movie* extern_movie)
+{
+       extern_movie->set_depth(num + DisplayObject::staticDepthOffset);
+       Levels::iterator it = _movies.find(extern_movie->get_depth());
+    if ( it == _movies.end() )
+    {
+        log_error("TESTME: loadMovie called on level %d which is not available 
at load time, skipped placement for now");
+        return; // skip
+    }
+
+    // TODO: rework this to avoid the double scan 
+       setLevel(num, extern_movie);
+}
+
 Movie*
 movie_root::getLevel(unsigned int num) const
 {
@@ -520,6 +547,9 @@
        // remove all intervals
        clearIntervalTimers();
 
+    // remove all loadMovie requests
+       clearLoadMovieRequests();
+
        // remove key/mouse listeners
        m_key_listeners.clear();
        m_mouse_listeners.clear();
@@ -1754,6 +1784,13 @@
         i->obj->setReachable();
     }
 
+    // Mark LoadMovieRequest handlers as reachable
+    for (LoadMovieRequests::const_iterator it=_loadMovieRequests.begin(),
+            end = _loadMovieRequests.end(); it != end; ++it)
+    {
+        (*it)->setReachable();
+    }
+
     // Mark resources reachable by queued action code
     for (int lvl=0; lvl<apSIZE; ++lvl)
     {
@@ -2139,7 +2176,8 @@
 
 void
 movie_root::loadMovie(const std::string& urlstr, const std::string& target,
-        const std::string& data, MovieClip::VariablesMethod method)
+        const std::string& data, MovieClip::VariablesMethod method,
+        as_object* handler)
 {
 
     /// URL security is checked in StreamProvider::getStream() down the
@@ -2159,53 +2197,167 @@
 
     log_debug("movie_root::loadMovie(%s, %s)", url.str(), target);
 
-    const std::string* postdata = NULL;
-
-    /// POST: send variables using the POST method.
-    if (method == MovieClip::METHOD_POST) postdata = &data;
-    _loadMovieRequests.push_front(LoadMovieRequest(url, target, postdata));
+    const std::string* postdata = (method == MovieClip::METHOD_POST) ? &data
+                                                                     : 0;
+
+    _loadMovieRequests.push_front(
+        new LoadMovieRequest(url, target, postdata, handler)
+    );
+
+    // TODO: start thread 
 }
 
 void
-movie_root::processLoadMovieRequest(const LoadMovieRequest& r)
-{
+movie_root::processLoadMovieRequest(LoadMovieRequest& r)
+{
+    const URL& url = r.getURL();
+    bool usePost = r.usePost();
+    const std::string* postdata = usePost ? &(r.getPostData()) : 0;
+
+    // TODO: make this load asyncronous !!
+       boost::intrusive_ptr<movie_definition> md (
+        MovieFactory::makeMovie(url, _runResources, NULL, true, postdata));
+    r.setCompleted(md);
+
+    bool completed = processCompletedLoadMovieRequest(r);
+    assert(completed);
+}
+
+/* private */
+bool
+movie_root::processCompletedLoadMovieRequest(const LoadMovieRequest& r)
+{
+    GNASH_REPORT_FUNCTION;
+
+    boost::intrusive_ptr<movie_definition> md;
+    if ( ! r.getCompleted(md) ) return false; // not completed yet
+
     const std::string& target = r.getTarget();
+    DisplayObject* targetDO = findCharacterByTarget(target);
+    as_object* handler = r.getHandler();
+
+    if ( ! md )
+    {
+
+        if ( targetDO && handler )
+        {
+            // Signal load error
+            // Tested not to happen if target isn't found at time of loading
+            //
+
+            as_value arg1(getObject(targetDO));
+
+            // FIXME: docs suggest the string can be either "URLNotFound" or
+            // "LoadNeverCompleted". This is neither of them:
+            as_value arg2("Failed to load movie or jpeg");
+
+            // FIXME: The last argument is HTTP status, or 0 if no connection
+            // was attempted (sandbox) or no status information is available
+            // (supposedly the Adobe mozilla plugin).
+            as_value arg3(0.0);
+
+            handler->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadError",
+                    arg1, arg2, arg3);
+        }
+        return true; // nothing to do, but completed
+    }
+
     const URL& url = r.getURL();
-    bool usePost = r.usePost();
-    const std::string& postData = r.getPostData();
-
-    if (target.compare(0, 6, "_level") == 0 &&
-            target.find_first_not_of("0123456789", 7) == std::string::npos)
-    {
-        unsigned int levelno = std::strtoul(target.c_str() + 6, NULL, 0);
-        log_debug(_("processLoadMovieRequest: Testing _level loading "
+
+       Movie* extern_movie = md->createMovie(*_vm.getGlobal());
+       if (!extern_movie)
+    {
+               log_error(_("Can't create Movie instance "
+                    "for definition loaded from %s"), url);
+               return true; // completed in any case...
+       }
+
+       // Parse query string
+       MovieClip::MovieVariables vars;
+       url.parse_querystring(url.querystring(), vars);
+    extern_movie->setVariables(vars);
+
+    if (targetDO)
+    {
+        targetDO->getLoadedMovie(extern_movie);
+    }
+    else
+    {
+        unsigned int levelno;
+        if (isLevelTarget(target, levelno))
+        {
+            log_debug(_("processCompletedLoadMovieRequest: _level loading "
                     "(level %u)"), levelno);
-        loadLevel(levelno, url);
-        return;
-    }
-
-    DisplayObject* ch = findCharacterByTarget(target);
-    if (!ch)
-    {
-        log_debug("Target %s of a loadMovie request doesn't exist at "
-                "processing time", target);
-        return;
-    }
-
-    MovieClip* sp = ch->to_movie();
-    if (!sp)
-    {
-        log_unimpl("loadMovie against a %s DisplayObject", typeName(*ch));
-        return;
-    }
-
-    if ( usePost )
-    {
-       sp->loadMovie(url, &postData);
-    }
-    else
-    {
-        sp->loadMovie(url);
+               extern_movie->set_depth(levelno + 
DisplayObject::staticDepthOffset);
+            setLevel(levelno, extern_movie);
+        }
+        else
+        {
+            log_debug("Target %s of a loadMovie request doesn't exist at "
+                  "load complete time", target);
+            return true;
+        }
+    }
+
+    if (handler && targetDO)
+    {
+        // Dispatch onLoadStart
+        // FIXME: should be signalled before starting to load
+        //        (0/-1 bytes loaded/total) but still with *new*
+        //        display object as target (ie: the target won't
+        //        contain members set either before or after loadClip.
+        handler->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadStart",
+            getObject(targetDO));
+
+        // Dispatch onLoadProgress
+        // FIXME: should be signalled every 65535 bytes ?
+        size_t bytesLoaded = md->get_bytes_loaded();
+        size_t bytesTotal = md->get_bytes_total();
+        handler->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadProgress",
+            getObject(targetDO), bytesLoaded, bytesTotal);
+
+        // Dispatch onLoadComplete
+        // FIXME: find semantic of last arg
+        handler->callMethod(NSV::PROP_BROADCAST_MESSAGE, "onLoadComplete",
+            getObject(targetDO), as_value(0.0));
+
+
+        // Displatch onLoadInit
+        
+        // This event must be dispatched when actions
+        // in first frame of loaded clip have been executed.
+        //
+        // Since getLoadedMovie or setLevel above will invoke
+        // stagePlacementCallback and thus queue all actions in first
+        // frame, we'll queue the
+        // onLoadInit call next, so it happens after the former.
+        //
+        std::auto_ptr<ExecutableCode> code(
+                new DelayedFunctionCall(handler, NSV::PROP_BROADCAST_MESSAGE, 
+                    "onLoadInit", getObject(targetDO)));
+
+        getRoot(*handler).pushAction(code, movie_root::apDOACTION);
+    }
+
+    return true;
+
+}
+
+/* private */
+void
+movie_root::processCompletedLoadMovieRequests()
+{
+    GNASH_REPORT_FUNCTION;
+
+    for (LoadMovieRequests::iterator it=_loadMovieRequests.begin();
+            it != _loadMovieRequests.end(); )
+    {
+        const LoadMovieRequest* lr=*it;
+        if ( processCompletedLoadMovieRequest(*lr) )
+        {
+            it = _loadMovieRequests.erase(it);
+            delete lr;
+        }
     }
 }
 
@@ -2218,9 +2370,10 @@
     for (LoadMovieRequests::iterator it=_loadMovieRequests.begin();
             it != _loadMovieRequests.end(); )
     {
-        const LoadMovieRequest& lr=*it;
-        processLoadMovieRequest(lr);
+        LoadMovieRequest* lr=*it;
+        processLoadMovieRequest(*lr);
         it = _loadMovieRequests.erase(it);
+        delete lr;
     }
 }
 

=== modified file 'libcore/movie_root.h'
--- a/libcore/movie_root.h      2009-11-06 07:39:15 +0000
+++ b/libcore/movie_root.h      2009-11-10 00:07:05 +0000
@@ -100,6 +100,7 @@
 #include <set>
 #include <bitset>
 #include <boost/noncopyable.hpp>
+#include <boost/thread/thread.hpp>
 
 // Forward declarations
 namespace gnash {
@@ -201,6 +202,17 @@
     ///
     bool loadLevel(unsigned int num, const URL& url);
 
+    /// Replace an existing level with a new movie
+    //
+    /// Depth will be assigned to external_movie by this function.
+    /// If the give level number doesn't exist an error is logged
+    /// and nothing else happens.
+    ///
+    /// This method is intended for use by xxx.loadMovie(yyy)
+    /// when 'xxx' is a top-level movie.
+    ///
+    void replaceLevel(unsigned int num, Movie* external_movie);
+
     /// Swap depth of a level (or two)
     //
     /// Character's depths are updated.
@@ -705,8 +717,13 @@
     ///                 key/value pairs
     /// @param method   The VariablesMethod to use for sending the data. If
     ///                 MovieClip::METHOD_NONE, no data will be sent.
+    /// @param handler  An object which will be signalled of load
+    ///                 events (onLoadStart, onLoadComplete, onLoadInit,
+    ///                 onLoadError). Can be null if caller doesn't care.
+    ///                 
     void loadMovie(const std::string& url, const std::string& target,
-            const std::string& data, MovieClip::VariablesMethod method);
+            const std::string& data, MovieClip::VariablesMethod method,
+            as_object* handler=0);
 
     /// Send a request to the hosting application (e.g. browser).
     //
@@ -936,17 +953,21 @@
     AbstractFsCallback* _fsCommandHandler;
 
     /// A load movie request
-    class LoadMovieRequest {
+    class LoadMovieRequest : boost::noncopyable {
     public:
         /// @param postdata
         ///   If not null POST method will be used for HTTP.
         ///
         LoadMovieRequest(const URL& u, const std::string& t,
-                const std::string* postdata)
+                const std::string* postdata, as_object* handler)
                 :
                 _target(t),
                 _url(u),
-                _usePost(false)
+                _usePost(false),
+                _mdef(0),
+                _completed(false),
+                _mutex(),
+                _handler(handler)
         {
             if ( postdata )
             {
@@ -959,23 +980,74 @@
         const URL& getURL() const { return _url; }
         const std::string& getPostData() const { return _postData; }
         bool usePost() const { return _usePost; }
+        as_object* getHandler() const { return _handler; }
+        void setReachable() const {
+            if (_handler) _handler->setReachable();
+        }
+
+        /// Get the loaded movie definition, if any
+        //
+        /// @param md the loaded movie_definition is copied here
+        ///           if it was impossible to create one.
+        ///
+        /// @return true if the request was completed, false otherwise.
+        ///
+        /// RULE: if return is FALSE param 'md' will be set to 0.
+        /// RULE: if return is TRUE  param 'md' may be set to 0 or non 0.
+        /// RULE: if parameter 'md' is set to non 0, TRUE must be returned.
+        ///
+        /// locks _mutex
+        ///
+        bool getCompleted(boost::intrusive_ptr<movie_definition>& md) const
+        {
+            boost::mutex::scoped_lock lock(_mutex);
+            md = _mdef;
+            return _completed;
+        }
+
+        /// Complete the request
+        //
+        /// @param md the loaded movie_definition, or 0 if
+        ///           it was impossible to create one.
+        ///
+        /// locks _mutex
+        ///
+        void setCompleted(boost::intrusive_ptr<movie_definition> md)
+        {
+            boost::mutex::scoped_lock lock(_mutex);
+            _mdef = md;
+            _completed = true;
+        }
 
     private:
         std::string _target;
         URL _url;
         bool _usePost;
         std::string _postData;
+        boost::intrusive_ptr<movie_definition> _mdef;
+        bool _completed;
+        mutable boost::mutex _mutex;
+        as_object* _handler;
     };
 
     /// Load movie requests
-    typedef std::list<LoadMovieRequest> LoadMovieRequests;
+    typedef std::list<LoadMovieRequest*> LoadMovieRequests;
     LoadMovieRequests _loadMovieRequests;
 
     /// Process all load movie requests
     void processLoadMovieRequests();
 
     /// Process a single load movie request
-    void processLoadMovieRequest(const LoadMovieRequest& r);
+    void processLoadMovieRequest(LoadMovieRequest& r);
+
+    /// Check a LoadMovieRequest and process if completed.
+    //
+    /// @return true if the request was completely processed.
+    ///
+    bool processCompletedLoadMovieRequest(const LoadMovieRequest& r);
+
+    /// Process all completed loadMovie requests.
+    void processCompletedLoadMovieRequests();
 
     /// Listeners container
     typedef std::list<DisplayObject*> CharacterList;
@@ -993,6 +1065,9 @@
     /// Delete all elements on the timers list
     void clearIntervalTimers();
 
+    /// Delete all LoadMovieRequests
+    void clearLoadMovieRequests();
+
     /// Execute expired timers
     void executeAdvanceCallbacks();
     

=== modified file 'libcore/vm/ExecutableCode.h'
--- a/libcore/vm/ExecutableCode.h       2009-10-27 09:44:54 +0000
+++ b/libcore/vm/ExecutableCode.h       2009-11-09 23:57:39 +0000
@@ -254,6 +254,64 @@
     DisplayObject* target;
 };
 
+/// This class is used to queue a function call action
+//
+/// Exact use is to queue onLoadInit, which should be invoked
+/// after actions of in first frame of a loaded movie are executed.
+/// Since those actions are queued the only way to execute something
+/// after them is to queue the function call as well.
+///
+/// The class might be made more general and accessible outside
+/// of the MovieClipLoader class. For now it only works for
+/// calling a function with a two argument.
+///
+class DelayedFunctionCall : public ExecutableCode
+{
+
+public:
+
+    DelayedFunctionCall(as_object* target, string_table::key name,
+            const as_value& arg1, const as_value& arg2)
+        :
+        _target(target),
+        _name(name),
+        _arg1(arg1),
+        _arg2(arg2)
+    {}
+
+
+    ExecutableCode* clone() const
+    {
+        return new DelayedFunctionCall(*this);
+    }
+
+    virtual void execute()
+    {
+        _target->callMethod(_name, _arg1, _arg2);
+    }
+
+#ifdef GNASH_USE_GC
+    /// Mark reachable resources (for the GC)
+    //
+    /// Reachable resources are:
+    ///  - the action target (_target)
+    ///
+    virtual void markReachableResources() const
+    {
+      _target->setReachable();
+      _arg1.setReachable();
+      _arg2.setReachable();
+    }
+#endif // GNASH_USE_GC
+
+private:
+
+    as_object* _target;
+    string_table::key _name;
+    as_value _arg1, _arg2;
+
+};
+
 
 
 } // namespace gnash

=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING  2009-11-03 22:43:22 +0000
+++ b/testsuite/swfdec/PASSING  2009-11-10 00:59:35 +0000
@@ -776,6 +776,8 @@
 moviecliploader-known-image-size-8.swf:32aaecb1e0735b6c94e980d21753e698
 moviecliploader-level-5.swf:fa26ae6da1ec573daae0ce5357a419c5
 moviecliploader-level-6.swf:cd9f65f627a47a906c4d140e8e518160
+moviecliploader-level-7.swf:b0ec6ee5047d1d5f49ccb9c22fc29b30
+moviecliploader-level-8.swf:18f7d36c66a71113613afc3b937d536e
 moviecliploader-properties-6.swf:85084f5ae86539dfedf525b204762dbf
 moviecliploader-properties-7.swf:f10fa0e2b443f46af6780465633ceb75
 moviecliploader-properties-8.swf:78fa86752025a314051eae11806c1498


reply via email to

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