CVSROOT: /sources/gnash Module name: gnash Changes by: Sandro Santilli <strk> 07/12/20 14:28:50
Modified files: . : ChangeLog server : as_object.cpp server/asobj : MovieClipLoader.cpp testsuite/actionscript.all: MovieClipLoader.as Log message: Send all MovieClipLoader event callbacks (we're still loading in the main thread though) CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.5225&r2=1.5226 http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_object.cpp?cvsroot=gnash&r1=1.87&r2=1.88 http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/MovieClipLoader.cpp?cvsroot=gnash&r1=1.38&r2=1.39 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/MovieClipLoader.as?cvsroot=gnash&r1=1.5&r2=1.6 Patches: Index: ChangeLog =================================================================== RCS file: /sources/gnash/gnash/ChangeLog,v retrieving revision 1.5225 retrieving revision 1.5226 diff -u -b -r1.5225 -r1.5226 --- ChangeLog 20 Dec 2007 02:01:38 -0000 1.5225 +++ ChangeLog 20 Dec 2007 14:28:49 -0000 1.5226 @@ -1,3 +1,11 @@ +2007-12-19 Sandro Santilli <[EMAIL PROTECTED]> + + * server/as_object.cpp: implement callMethod taking 3 args. + * server/asobj/MovieClipLoader.cpp: cleanup interfaces, send + all required events (altought still not in async mode). + * testsuite/actionscript.all/MovieClipLoader.as: test events + execution. + 2007-12-19 Rob Savoye <[EMAIL PROTECTED]> * utilities/soldumper: Dump the contents of any .sol file. Useful Index: server/as_object.cpp =================================================================== RCS file: /sources/gnash/gnash/server/as_object.cpp,v retrieving revision 1.87 retrieving revision 1.88 diff -u -b -r1.87 -r1.88 --- server/as_object.cpp 19 Dec 2007 00:10:05 -0000 1.87 +++ server/as_object.cpp 20 Dec 2007 14:28:50 -0000 1.88 @@ -964,6 +964,39 @@ return ret; } +as_value +as_object::callMethod(string_table::key methodName, + const as_value& arg0, const as_value& arg1, const as_value& arg2) +{ + as_value ret; + as_value method; + + if (! get_member(methodName, &method)) + { + return ret; + } + + as_environment env; + +#ifndef NDEBUG + size_t origStackSize = env.stack_size(); +#endif + + env.push(arg2); + env.push(arg1); + env.push(arg0); + + ret = call_method(method, &env, this, 3, env.stack_size()-1); + + env.drop(3); + +#ifndef NDEBUG + assert(origStackSize == env.stack_size()); +#endif + + return ret; +} + as_object* as_object::get_path_element(string_table::key key) { Index: server/asobj/MovieClipLoader.cpp =================================================================== RCS file: /sources/gnash/gnash/server/asobj/MovieClipLoader.cpp,v retrieving revision 1.38 retrieving revision 1.39 diff -u -b -r1.38 -r1.39 --- server/asobj/MovieClipLoader.cpp 28 Nov 2007 12:47:04 -0000 1.38 +++ server/asobj/MovieClipLoader.cpp 20 Dec 2007 14:28:50 -0000 1.39 @@ -38,6 +38,7 @@ #include "Object.h" // for getObjectInterface #include "AsBroadcaster.h" // for initializing self as a broadcaster #include "namedStrings.h" +#include "array.h" // for _listeners construction #include <typeinfo> #include <string> @@ -58,6 +59,12 @@ o.init_member("unloadClip", new builtin_function(moviecliploader_unloadclip)); o.init_member("getProgress", new builtin_function(moviecliploader_getprogress)); + // NOTE: we want addListener/removeListener/broadcastMessage + // but don't what the _listeners property here... + // TODO: add an argument to AsBroadcaster::initialize skip listeners ? + AsBroadcaster::initialize(o); + o.delProperty(NSV::PROP_uLISTENERS); + #if 0 // Load the default event handlers. These should really never // be called directly, as to be useful they are redefined @@ -156,7 +163,7 @@ _mcl.bytes_loaded = 0; _mcl.bytes_total = 0; - AsBroadcaster::initialize(*this); + set_member(NSV::PROP_uLISTENERS, new as_array_object()); } MovieClipLoader::~MovieClipLoader() @@ -177,9 +184,6 @@ bool MovieClipLoader::loadClip(const std::string& url_str, sprite_instance& target) { - // Prepare function call for events... - //env.push(as_value(&target)); - //fn_call events_call(this, &env, 1, 0); URL url(url_str.c_str(), get_base_url()); @@ -187,18 +191,29 @@ log_msg(_(" resolved url: %s"), url.str().c_str()); #endif - // Call the callback since we've started loading the file - // TODO: probably we should move this below, after - // the loading thread actually started - dispatchEvent("onLoadStart", as_value(&target)); + string_table& st = _vm.getStringTable(); bool ret = target.loadMovie(url); if ( ! ret ) { - // TODO: dispatchEvent("onLoadError", ...) + // TODO: find semantic of last argument + callMethod(st.find("onLoadError"), as_value(&target), as_value("Failed to load movie or jpeg"), as_value(0)); + return false; } + // Dispatch onLoadStart + callMethod(st.find("onLoadStart"), as_value(&target)); + + // Dispatch onLoadProgress + struct mcl *mcl_data = getProgress(&target); + // the callback since we're done loading the file + mcl_data->bytes_loaded = target.get_bytes_loaded(); + mcl_data->bytes_total = target.get_bytes_total(); + callMethod(st.find("onLoadProgress"), as_value(&target), mcl_data->bytes_loaded, mcl_data->bytes_total); + + // Dispatch onLoadComplete + callMethod(st.find("onLoadComplete"), as_value(&target), as_value(0)); // TODO: find semantic of last arg /// This event must be dispatched when actions /// in first frame of loaded clip have been executed. @@ -210,23 +225,7 @@ /// TODO: check if we need to place it before calling /// this function though... /// - //dispatchEvent("onLoadInit", events_call); - dispatchEvent("onLoadInit", as_value(&target)); - - struct mcl *mcl_data = getProgress(&target); - - // the callback since we're done loading the file - // FIXME: these both probably shouldn't be set to the same value - //mcl_data->bytes_loaded = stats.st_size; - //mcl_data->bytes_total = stats.st_size; - mcl_data->bytes_loaded = 666; // fake values for now - mcl_data->bytes_total = 666; - - // TODO: dispatchEvent("onLoadProgress", ...) - - log_unimpl (_("FIXME: MovieClipLoader calling onLoadComplete *before* movie has actually been fully loaded (cheating)")); - //dispatchEvent("onLoadComplete", events_call); - dispatchEvent("onLoadComplete", as_value(&target)); + callMethod(st.find("onLoadInit"), as_value(&target)); return true; } @@ -256,31 +255,37 @@ boost::intrusive_ptr<MovieClipLoader> ptr = ensureType<MovieClipLoader>(fn.this_ptr); - as_value& url_arg = fn.arg(0); -#if 0 // whatever it is, we'll need a string, the check below would only be worth - // IF_VERBOSE_MALFORMED_SWF, but I'm not sure it's worth the trouble of - // checking it, and chances are that the reference player will be trying - // to convert to string anyway... - if ( ! url_arg.is_string() ) + if ( fn.nargs < 2 ) { - log_swferror(_("MovieClipLoader.loadClip() first argument is not a string (%s)"), url_arg.to_string()); + IF_VERBOSE_ASCODING_ERRORS( + std::stringstream ss; fn.dump_args(ss); + log_aserror(_("MovieClipLoader.loadClip(%s): missing arguments"), ss.str().c_str()); + ); return as_value(false); - return; } -#endif + + as_value url_arg = fn.arg(0); std::string str_url = url_arg.to_string(); - character* target = fn.env().find_target(fn.arg(1).to_string()); + as_value tgt_arg = fn.arg(1); + std::string tgt_str = tgt_arg.to_string(); + character* target = fn.env().find_target(tgt_str); if ( ! target ) { - log_error(_("Could not find target %s"), fn.arg(1).to_string().c_str()); + IF_VERBOSE_ASCODING_ERRORS( + log_aserror(_("Could not find target %s (evaluated from %s)"), + tgt_str.c_str(), tgt_arg.to_debug_string().c_str()); + ); return as_value(false); } - sprite_instance* sprite = dynamic_cast<sprite_instance*>(target); + + sprite_instance* sprite = target->to_movie(); if ( ! sprite ) { - log_error(_("Target is not a sprite instance (%s)"), - typeid(*target).name()); + IF_VERBOSE_ASCODING_ERRORS( + log_aserror(_("Target %s is not a sprite instance (%s)"), + target->getTarget().c_str(), typeName(*target).c_str()); + ); return as_value(false); } @@ -289,9 +294,10 @@ str_url.c_str(), (void*)sprite); #endif - bool ret = ptr->loadClip(str_url, *sprite); + ptr->loadClip(str_url, *sprite); - return as_value(ret); + // We always want to return true unless something went wrong + return as_value(true); } @@ -343,9 +349,6 @@ if ( cl == NULL ) { cl=new builtin_function(&moviecliploader_new, getMovieClipLoaderInterface()); - // replicate all interface to class, to be able to access - // all methods as static functions - attachMovieClipLoaderInterface(*cl); // not sure we should be doing this.. } global.init_member("MovieClipLoader", cl.get()); //as_value(moviecliploader_new)); //log_msg(_("MovieClipLoader class @ %p"), cl.get()); Index: testsuite/actionscript.all/MovieClipLoader.as =================================================================== RCS file: /sources/gnash/gnash/testsuite/actionscript.all/MovieClipLoader.as,v retrieving revision 1.5 retrieving revision 1.6 diff -u -b -r1.5 -r1.6 --- testsuite/actionscript.all/MovieClipLoader.as 2 Oct 2007 12:17:47 -0000 1.5 +++ testsuite/actionscript.all/MovieClipLoader.as 20 Dec 2007 14:28:50 -0000 1.6 @@ -21,43 +21,270 @@ // compile this test case with Ming makeswf, and then // execute it like this gnash -1 -r 0 -v out.swf -rcsid="$Id: MovieClipLoader.as,v 1.5 2007/10/02 12:17:47 strk Exp $"; +rcsid="$Id: MovieClipLoader.as,v 1.6 2007/12/20 14:28:50 strk Exp $"; #include "check.as" +//#define MEDIA(x) x + // MovieClipLoader was added in player7 #if OUTPUT_VERSION >= 7 check_equals(typeOf(MovieClipLoader), 'function'); +check_equals(typeOf(MovieClipLoader.prototype), 'object'); +check(MovieClipLoader.prototype.hasOwnProperty('loadClip')); +check(MovieClipLoader.prototype.hasOwnProperty('unloadClip')); +check(MovieClipLoader.prototype.hasOwnProperty('getProgress')); +check(MovieClipLoader.prototype.hasOwnProperty('addListener')); +check(MovieClipLoader.prototype.hasOwnProperty('removeListener')); +check(MovieClipLoader.prototype.hasOwnProperty('broadcastMessage')); +check_equals(typeOf(MovieClipLoader._listeners), 'undefined'); var mcl = new MovieClipLoader(); check_equals(typeOf(mcl), 'object'); -check_equals(typeOf(mcl.addListener), 'function'); -check_equals(typeOf(mcl.getProgress), 'function'); +check(mcl instanceOf MovieClipLoader); + check_equals(typeOf(mcl.loadClip), 'function'); +check(!mcl.hasOwnProperty('loadClip')); + +check_equals(typeOf(mcl.unloadClip), 'function'); +check(!mcl.hasOwnProperty('unloadClip')); + +check_equals(typeOf(mcl.getProgress), 'function'); +check(!mcl.hasOwnProperty('getProgress')); + +check_equals(typeOf(mcl.addListener), 'function'); +check(!mcl.hasOwnProperty('addListener')); + check_equals(typeOf(mcl.removeListener), 'function'); +check(!mcl.hasOwnProperty('removeListener')); + check_equals(typeOf(mcl.broadcastMessage), 'function'); -check_equals(typeOf(mcl.unloadClip), 'function'); -check(mcl instanceOf MovieClipLoader); +check(!mcl.hasOwnProperty('broadcastMessage')); +check_equals(typeOf(mcl._listeners), 'object'); +check(mcl.hasOwnProperty('_listeners')); + +MovieClipLoader.prototype.bm = MovieClipLoader.prototype.broadcastMessage; +MovieClipLoader.prototype.broadcastMessage = function(arg1, arg2, arg3, arg4) +{ + note("Broadcasting "+arg1); + //this.bm(arg1, arg2, arg3, arg4); + this.bm.apply(this, arguments); +}; + +//--------------------------------------------------------- +// Test loadClip and events +//--------------------------------------------------------- +// // TODO: test even handlers (actionscript.all framework // not enough for this) // -// Invoked when a file loaded with MovieClipLoader.loadClip() has completely downloaded. -// MovieClipLoader.onLoadComplete -// // Invoked when a file loaded with MovieClipLoader.loadClip() has failed to load. // MovieClipLoader.onLoadError // -// Invoked when the actions on the first frame of the loaded clip have been executed. -// MovieClipLoader.onLoadInit +// Invoked when a call to MovieClipLoader.loadClip() has successfully begun to download a file. +// MovieClipLoader.onLoadStart // // Invoked every time the loading content is written to disk during the loading process. // MovieClipLoader.onLoadProgress // -// Invoked when a call to MovieClipLoader.loadClip() has successfully begun to download a file. -// MovieClipLoader.onLoadStart +// Invoked when a file loaded with MovieClipLoader.loadClip() has completely downloaded. +// MovieClipLoader.onLoadComplete // +// Invoked when the actions on the first frame of the loaded clip have been executed. +// MovieClipLoader.onLoadInit +// +//--------------------------------------------------------- + +dumpObj = function(o, lvl) +{ + if ( typeof(lvl) == 'undefined' ) lvl=0; + for (var i in o) + { + note(lvl+' - '+i+': '+o[i]+' ('+typeof(o[i])+')'); + if ( typeof(o[i]) == 'object' ) dumpObj(o[i], lvl+1); + } +}; + + +createEmptyMovieClip("loadtarget", 10); + +expected = { + target: undefined +}; + +resetState = function() +{ + state = { + onLoadStartCalls:0, + onLoadErrorCalls:0, + onLoadProgressCalls:0, + onLoadCompleteCalls:0, + onLoadInitCalls:0 + }; +}; +totalProgressCalls=0; + +mcl.onLoadError = function(target, msg, n) +{ + check_equals(arguments.length, 3); + check_equals(target, expected.target); + note("onLoadError called ("+msg+")"); + if ( state.nextFunction == undefined ) + { + // we don't know how many times onLoadProgress will be called + // so we have that handler increment a totalProgressCalls and + // we use that value to figure out how many tests to expect to + // be run (6 tests each onLoadProgress call). + // Note that if we miss to call onLoadProgress at all we'd catch + // the bug from supposedly subsequent callbacks, which check for + // a local flag set by the onLoadProgress handler. + // + progCallbackTests = totalProgressCalls*6; + note("Number of onLoadProgress runs: "+totalProgressCalls+" - tests: "+progCallbackTests); + if ( expect.failtotals ) { + xcheck_totals(expected.totals + progCallbackTests); + } else { + check_totals(expected.totals + progCallbackTests); + } + play(); + } + else + { + state.nextFunction(); + } + //dumpObj(arguments); +}; + +mcl.onLoadStart = function(target) +{ + check_equals(arguments.length, 1); + check_equals(target, expected.target); + state.onLoadStartCalls++; + //note("onLoadStart called with "+arguments.length+" args:"); dumpObj(arguments); +}; + +mcl.onLoadProgress = function(target, bytesLoaded, bytesTotal) +{ + check_equals(arguments.length, 3); + check_equals(target, expected.target); + check_equals(state.onLoadStartCalls, 1); + check_equals(typeof(bytesLoaded), 'number') + check_equals(typeof(bytesTotal), 'number') + check(bytesTotal <= bytesTotal); + ++state.onLoadProgressCalls; + ++totalProgressCalls; + //note("onLoadProgress called with "+arguments.length+" args:"); dumpObj(arguments); +}; + +mcl.onLoadComplete = function(target, n) +{ + check_equals(arguments.length, 2); + check_equals(target, expected.target); + check_equals(state.onLoadStartCalls, 1); + check(state.onLoadProgressCalls > 0); + check_equals(typeof(n), 'number'); // what is this ? + state.onLoadCompleteCalls++; + + note("onLoadComplete second arg is "+n+" ("+typeof(n)+")"); +}; + +mcl.onLoadInit = function(target) +{ + check_equals(arguments.length, 1); + check_equals(target, expected.target); + check_equals(state.onLoadStartCalls, 1); + check(state.onLoadProgressCalls > 0); + check_equals(state.onLoadCompleteCalls, 1); + state.onLoadInitCalls++; + + //note("target.var1: "+target.var1); + //note("onLoadInit called with "+arguments.length+" args:"); dumpObj(arguments); + if ( state.nextFunction == undefined ) + { + // we don't know how many times onLoadProgress will be called + // so we have that handler increment a totalProgressCalls and + // we use that value to figure out how many tests to expect to + // be run (6 tests each onLoadProgress call). + // Note that if we miss to call onLoadProgress at all we'd catch + // the bug from supposedly subsequent callbacks, which check for + // a local flag set by the onLoadProgress handler. + // + progCallbackTests = totalProgressCalls*6; + note("Number of onLoadProgress runs: "+totalProgressCalls+" - tests: "+progCallbackTests); + if ( expect.failtotals ) { + xcheck_totals(expected.totals + progCallbackTests); + } else { + check_totals(expected.totals + progCallbackTests); + } + + play(); + } + else + { + state.nextFunction(); + } +}; + +check( ! mcl.loadClip() ); +check( ! mcl.loadClip( MEDIA(vars.txt) ) ); + +check( ! mcl.loadClip( MEDIA(vars.txt), 'unexistent' ) ); + +function test1() +{ + resetState(); + state.nextFunction = test2; + expected.target = _root.loadtarget; + check( mcl.loadClip( MEDIA(unexistent), 'loadtarget' ) ); +} + +function test2() +{ + resetState(); + state.nextFunction = test3; + expected.target = _root.loadtarget; + check( mcl.loadClip( MEDIA(vars.txt), 'loadtarget' ) ); +} + +function test3() +{ + resetState(); + state.nextFunction = undefined; + expected.target = _root.loadtarget; + + // set expected.totals when willing to end the test + // we don't know how many times onLoadProgress will be called + // so we only count the tests we can determine. + // The onLoadInit function will do the rest, by checking the actual + // number of times onLoadProgress was called and add to our expected + // count (appropriately multiplied to count *every* test in the + // onLoadProgress) + // + // subtract the number of progress callback runs reported when playing from the totals to get the correct number + // + expected.totals = 57; + // gnash doesn't call onLoadInit if the data at the url is not an SWF or JPG + // (or whatever else can become a movie_instance), while the PP does. + // So in this testcase, the attempt to load vars.txt is invalid for Gnash + // (triggers onLoadError) + // + expected.failtotals = true; + + + loadtarget._y = 200; + loadtarget._x = 200; + loadtarget._alpha = 20; + check( mcl.loadClip( MEDIA(green.jpg), 'loadtarget' ) ); +} + +test1(); + +stop(); + +#else // OUTPUT_VERSION < 7 -#endif // OUTPUT_VERSION >= 7 totals(); + +#endif _______________________________________________ Gnash-commit mailing list Gnash-commit@gnu.org http://lists.gnu.org/mailman/listinfo/gnash-commit