gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash ChangeLog server/array.cpp server/array.h...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog server/array.cpp server/array.h...
Date: Tue, 11 Sep 2007 17:01:24 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  07/09/11 17:01:24

Modified files:
        .              : ChangeLog 
        server         : array.cpp array.h as_object.cpp as_object.h 
        server/asobj   : Global.cpp Makefile.am 
        testsuite/actionscript.all: AsBroadcaster.as 
Added files:
        server/asobj   : AsBroadcaster.cpp AsBroadcaster.h 

Log message:
                * server/array.{cpp,h}: add removeFirst and visitAll methods.
                * server/as_object.{cpp,h}: add getMember and callMethod 
memebers
                  for ActionScript-like coding.
                * server/asobj/: Makefile.am, Global.cpp, AsBroadcaster.{cpp,h}:
                  First draft at AsBroadcaster. NOTE: this is not 100% 
compatible
                  but contains some special code to handle corner cases for 
compatbility
                  sake (mostly to avoid breaking swfdec testcases). The normal 
case
                  will still be faster then the average one.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.4271&r2=1.4272
http://cvs.savannah.gnu.org/viewcvs/gnash/server/array.cpp?cvsroot=gnash&r1=1.76&r2=1.77
http://cvs.savannah.gnu.org/viewcvs/gnash/server/array.h?cvsroot=gnash&r1=1.33&r2=1.34
http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_object.cpp?cvsroot=gnash&r1=1.59&r2=1.60
http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_object.h?cvsroot=gnash&r1=1.66&r2=1.67
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Global.cpp?cvsroot=gnash&r1=1.67&r2=1.68
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Makefile.am?cvsroot=gnash&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/AsBroadcaster.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/AsBroadcaster.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/AsBroadcaster.as?cvsroot=gnash&r1=1.1&r2=1.2

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.4271
retrieving revision 1.4272
diff -u -b -r1.4271 -r1.4272
--- ChangeLog   11 Sep 2007 15:35:42 -0000      1.4271
+++ ChangeLog   11 Sep 2007 17:01:22 -0000      1.4272
@@ -1,3 +1,14 @@
+2007-09-11 Sandro Santilli <address@hidden>
+
+       * server/array.{cpp,h}: add removeFirst and visitAll methods.
+       * server/as_object.{cpp,h}: add getMember and callMethod memebers
+         for ActionScript-like coding.
+       * server/asobj/: Makefile.am, Global.cpp, AsBroadcaster.{cpp,h}:
+         First draft at AsBroadcaster. NOTE: this is not 100% compatible
+         but contains some special code to handle corner cases for compatbility
+         sake (mostly to avoid breaking swfdec testcases). The normal case
+         will still be faster then the average one.
+
 2007-09-11 Benjamin Wolsey <address@hidden>
 
        * server/gnash.h: add more keycodes.

Index: server/array.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/array.cpp,v
retrieving revision 1.76
retrieving revision 1.77
diff -u -b -r1.76 -r1.77
--- server/array.cpp    1 Sep 2007 01:59:33 -0000       1.76
+++ server/array.cpp    11 Sep 2007 17:01:23 -0000      1.77
@@ -765,6 +765,20 @@
        return ret;
 }
 
+bool
+as_array_object::removeFirst(const as_value& v, as_environment& env)
+{
+       for (iterator it = elements.begin(); it != elements.end(); ++it)
+       {
+               if ( v.equals(*it, env) )
+               {
+                       elements.erase(it);
+                       return true;
+               }
+       }
+       return false;
+}
+
 /* virtual public, overriding as_object::get_member */
 bool
 as_array_object::get_member(const std::string& name, as_value *val)

Index: server/array.h
===================================================================
RCS file: /sources/gnash/gnash/server/array.h,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -b -r1.33 -r1.34
--- server/array.h      30 Aug 2007 01:02:49 -0000      1.33
+++ server/array.h      11 Sep 2007 17:01:23 -0000      1.34
@@ -60,6 +60,17 @@
        typedef container::const_iterator const_iterator;
        typedef container::iterator iterator;
 
+       /// Visit all elements 
+       //
+       /// The visitor class will have to expose a visit(as_value&) method
+       ///
+       template<class V> void visitAll(V& v)
+       {
+               for (iterator i=elements.begin(), ie=elements.end(); i!=ie; ++i)
+               {
+                       v.visit(*i);
+               }
+       }
 
        /// Sort flags
        enum SortFlags {
@@ -162,6 +173,18 @@
        std::auto_ptr<as_array_object> slice(
                unsigned int start, unsigned int one_past_end);
 
+       /// Remove first element matching the given value
+       //
+       /// Return true if any element was removed, false otherwise
+       ///
+       /// @param v
+       ///     The value to compare elements against
+       ///
+       /// @param env
+       ///     The environment to use when comparing (needed by 
as_value::equals)
+       ///
+       bool removeFirst(const as_value& v, as_environment& env);
+
        /// \brief
        /// Substitute 'len' elements from 'start' with elements from
        /// the given array.

Index: server/as_object.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_object.cpp,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -b -r1.59 -r1.60
--- server/as_object.cpp        2 Sep 2007 00:12:48 -0000       1.59
+++ server/as_object.cpp        11 Sep 2007 17:01:23 -0000      1.60
@@ -30,9 +30,7 @@
 #include "GnashException.h"
 #include "fn_call.h" // for generic methods
 #include "Object.h" // for getObjectInterface
-#ifdef NEW_KEY_LISTENER_LIST_DESIGN
-  #include "action.h" // for call_method
-#endif                                 
+#include "action.h" // for call_method
 #include <set>
 #include <string>
 #include <boost/algorithm/string/case_conv.hpp>
@@ -661,4 +659,67 @@
 }
 #endif 
 
+as_value
+as_object::getMember(const std::string& name)
+{
+       as_value ret;
+       get_member(PROPNAME(name), &ret);
+       return ret;
+}
+
+as_value
+as_object::callMethod(const std::string& methodName, as_environment& env)
+{
+       as_value ret;
+       as_value method;
+
+       if ( ! get_member(methodName, &method) )
+       {
+               return ret;
+       }
+
+       return call_method(method, &env, this, 0, env.stack_size());
+}
+
+as_value
+as_object::callMethod(const std::string& methodName, as_environment& env, 
const as_value& arg0)
+{
+       as_value ret;
+       as_value method;
+
+       if ( ! get_member(methodName, &method) )
+       {
+               return ret;
+       }
+
+       env.push(arg0);
+
+       ret = call_method(method, &env, this, 1, env.stack_size()-1);
+
+       env.drop(1);
+
+       return ret;
+}
+
+as_value
+as_object::callMethod(const std::string& methodName, as_environment& env, 
const as_value& arg0, const as_value& arg1)
+{
+       as_value ret;
+       as_value method;
+
+       if ( ! get_member(methodName, &method) )
+       {
+               return ret;
+       }
+
+       env.push(arg0);
+       env.push(arg1);
+
+       ret = call_method(method, &env, this, 2, env.stack_size()-2);
+
+       env.drop(2);
+
+       return ret;
+}
+
 } // end of gnash namespace

Index: server/as_object.h
===================================================================
RCS file: /sources/gnash/gnash/server/as_object.h,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -b -r1.66 -r1.67
--- server/as_object.h  2 Sep 2007 00:12:48 -0000       1.66
+++ server/as_object.h  11 Sep 2007 17:01:23 -0000      1.67
@@ -274,6 +274,49 @@
                return get_member_default(name, val);
        }
 
+       /// Get a member as_value by name in an AS-compatible way
+       //
+       /// NOTE that this method is non-const becase a property
+       ///      could also be a getter/setter and we can't promise
+       ///      that the 'getter' won't change this object trough
+       ///      use of the 'this' reference. 
+       ///
+       /// @param name
+       ///     Name of the property. Will be converted to lowercase
+       ///     if the current VM is initialized for a  target
+       ///     up to SWF6.
+       ///
+       /// @return value of the member (possibly undefined),
+       ///     or undefined if not found. Use get_member if you
+       ///     need to know wheter it was found or not.
+       ///
+       as_value getMember(const std::string& name);
+
+       /// Call a method of this object in an AS-compatible way
+       //
+       /// @param name
+       ///     Name of the method. Will be converted to lowercase
+       ///     if the current VM is initialized for a  target
+       ///     up to SWF6.
+       ///
+       /// @param env
+       ///     The environment to use for setting up call frame stack
+       ///
+       /// @param nargs
+       ///     Number of arguments
+       ///
+       /// @param ...
+       ///     nargs as_value references
+       ///
+       /// @return value of the member (possibly undefined),
+       ///     or undefined if not found. Use get_member if you
+       ///     need to know wheter it was found or not.
+       ///
+       as_value callMethod(const std::string& name, as_environment& env);
+       as_value callMethod(const std::string& name, as_environment& env, const 
as_value& arg0);
+       as_value callMethod(const std::string& name, as_environment& env, const 
as_value& arg0, const as_value& arg1);
+       as_value callMethod(const std::string& name, as_environment& env, const 
as_value& arg0, const as_value& arg1, const as_value& arg2);
+
        /// Delete a property of this object, unless protected from deletion.
        //
        /// This function does *not* recurse in this object's prototype.

Index: server/asobj/Global.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Global.cpp,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -b -r1.67 -r1.68
--- server/asobj/Global.cpp     11 Sep 2007 05:46:31 -0000      1.67
+++ server/asobj/Global.cpp     11 Sep 2007 17:01:23 -0000      1.68
@@ -17,7 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-/* $Id: Global.cpp,v 1.67 2007/09/11 05:46:31 zoulunkai Exp $ */
+/* $Id: Global.cpp,v 1.68 2007/09/11 17:01:23 strk Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -28,6 +28,7 @@
 #include "as_value.h"
 #include "as_function.h" // for function_class_init
 #include "array.h"
+#include "AsBroadcaster.h"
 #include "Boolean.h"
 #include "Camera.h"
 #include "Color.h"
@@ -437,6 +438,10 @@
        init_member("NaN", as_value(NAN));
        init_member("Infinity", as_value(INFINITY));
 
+       // TODO: check if this is available in SWF4
+       // (for SWF5 it just exists as a useless function, it seems)
+       AsBroadcaster_init(*this);
+
        if ( vm.getSWFVersion() < 6 ) goto extscan;
        //-----------------------
        // SWF6

Index: server/asobj/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Makefile.am,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- server/asobj/Makefile.am    27 Aug 2007 18:13:43 -0000      1.43
+++ server/asobj/Makefile.am    11 Sep 2007 17:01:23 -0000      1.44
@@ -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: Makefile.am,v 1.43 2007/08/27 18:13:43 cmusick Exp $
+# $Id: Makefile.am,v 1.44 2007/09/11 17:01:23 strk Exp $
 
 AUTOMAKE_OPTIONS = 
 
@@ -43,6 +43,7 @@
 
 
 libgnashasobjs_la_SOURCES = \
+        AsBroadcaster.cpp \
         BevelFilter_as.cpp \
         BitmapFilter_as.cpp \
        Boolean.cpp     \
@@ -85,6 +86,7 @@
        $(NULL)
 
 noinst_HEADERS = \
+        AsBroadcaster.h \
         BevelFilter_as.h \
         BitmapFilter_as.h \
        Boolean.h       \

Index: testsuite/actionscript.all/AsBroadcaster.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/AsBroadcaster.as,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- testsuite/actionscript.all/AsBroadcaster.as 30 Aug 2007 09:47:36 -0000      
1.1
+++ testsuite/actionscript.all/AsBroadcaster.as 11 Sep 2007 17:01:23 -0000      
1.2
@@ -19,7 +19,7 @@
 // compile this test case with Ming makeswf, and then
 // execute it like this gnash -1 -r 0 -v out.swf
 
-rcsid="$Id: AsBroadcaster.as,v 1.1 2007/08/30 09:47:36 strk Exp $";
+rcsid="$Id: AsBroadcaster.as,v 1.2 2007/09/11 17:01:23 strk Exp $";
 
 #include "check.as"
 
@@ -28,19 +28,23 @@
 note();
 note("AsBroadcaster exists but doesn't provide any 'prototype' or 'initialize' 
for SWF < 6");
 
-xcheck_equals(typeof(AsBroadcaster), 'function'); // ???
-check_equals(typeof(AsBroadcaster.prototype), 'undefined'); 
+check_equals(typeof(AsBroadcaster), 'function'); // ???
+xcheck_equals(typeof(AsBroadcaster.prototype), 'undefined'); 
 check_equals(typeof(AsBroadcaster.initialize), 'undefined');
 
 #else // OUTPUT_VERSION >= 6
 
-xcheck_equals(typeof(AsBroadcaster), 'function'); // ???
-xcheck_equals(typeof(AsBroadcaster.prototype), 'object'); 
-xcheck_equals(typeof(AsBroadcaster.initialize), 'function');
+check_equals(typeof(AsBroadcaster), 'function'); // ???
+check_equals(typeof(AsBroadcaster.prototype), 'object'); 
+check_equals(AsBroadcaster.__proto__, Function.prototype); 
+check_equals(typeof(AsBroadcaster.initialize), 'function');
+check(AsBroadcaster.hasOwnProperty('initialize'));
+check(!AsBroadcaster.prototype.hasOwnProperty('initialize'));
 
 bc = new AsBroadcaster;
-xcheck_equals(typeof(bc), 'object');
-xcheck(bc instanceof AsBroadcaster);
+check_equals(typeof(bc), 'object');
+check(bc instanceof AsBroadcaster);
+check(bc instanceof Object);
 check_equals(typeof(bc.addListener), 'undefined');
 check_equals(typeof(bc.removeListener), 'undefined');
 check_equals(typeof(bc.broadcastMessage), 'undefined');
@@ -55,77 +59,77 @@
 
 AsBroadcaster.initialize(bcast);
 
-xcheck_equals(typeof(bcast._listeners), 'object');
-xcheck(bcast._listeners instanceof Array);
-xcheck_equals(bcast._listeners.length, 0);
-xcheck_equals(typeof(bcast.addListener), 'function');
-xcheck_equals(typeof(bcast.removeListener), 'function');
-xcheck_equals(typeof(bcast.broadcastMessage), 'function');
+check_equals(typeof(bcast._listeners), 'object');
+check(bcast._listeners instanceof Array);
+check_equals(bcast._listeners.length, 0);
+check_equals(typeof(bcast.addListener), 'function');
+check_equals(typeof(bcast.removeListener), 'function');
+check_equals(typeof(bcast.broadcastMessage), 'function');
 
 //--------------------------------
 // Some insane calls...
 //--------------------------------
 
 ret = bcast.addListener();
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 1); // !!
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 1); // !!
 
 ret = bcast.addListener();
-xcheck_equals(bcast._listeners.length, 1); // undefined was already there as 
an element...
+check_equals(bcast._listeners.length, 1); // undefined was already there as an 
element...
 
 ret = bcast.addListener(2);
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 2); // !!
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 2); // !!
 
 ret = bcast.addListener(2);
-xcheck_equals(bcast._listeners.length, 2); // 2 was already there as an 
element ...
+check_equals(bcast._listeners.length, 2); // 2 was already there as an element 
...
 ret = bcast.addListener(3);
-xcheck_equals(bcast._listeners.length, 3); // 3 is a new element
+check_equals(bcast._listeners.length, 3); // 3 is a new element
 
 ret = bcast.removeListener(); // will remove the undefined value !
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 2); // element 'undefined' was removed
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 2); // element 'undefined' was removed
 
 ret = bcast.removeListener(2); // will remove the element number:2 !
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 1); // element '2' was removed
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 1); // element '2' was removed
 
 ret = bcast.removeListener(3); // will remove the element number:3 !
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 0); // element '3' was removed
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 0); // element '3' was removed
 
 ret = bcast.removeListener(); // no such element ?
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, false);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, false);
 
 o = new Object; o.valueOf = function() { return 'yes I am'; };
 bcast.addListener(o);
-xcheck_equals(bcast._listeners.length, 1); 
+check_equals(bcast._listeners.length, 1); 
 ret = bcast.removeListener('yes I am'); // valueOf invoked
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 0); // element '3' was removed
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 0); // element '3' was removed
 
 o.addListener = bcast.addListener;
 check_equals(typeof(o._listeners), 'undefined');
 check_equals(typeof(o.removeListenerCalled), 'undefined');
 ret = o.addListener(); // automatically attempts to call o.removeListener()
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 check_equals(typeof(o._listeners), 'undefined');
 
 o.removeListener = function() { this.removeListenerCalled = true; };
 ret = o.addListener(); // automatically calls o.removeListener()
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 check_equals(typeof(o._listeners), 'undefined');
-xcheck_equals(typeof(o.removeListenerCalled), 'boolean');
-xcheck_equals(o.removeListenerCalled, true);
+check_equals(typeof(o.removeListenerCalled), 'boolean');
+check_equals(o.removeListenerCalled, true);
 
 o.removeListener = bcast.removeListener;
 o._listeners = new Object();
@@ -134,9 +138,10 @@
 o._listeners.length = 1;
 o._listeners['0'] = 5;
 ret = o.addListener(5); // automatically calls o._listeners.splice and 
o._listeners.push
-xcheck_equals(o._listeners.pushCalled, true);
-xcheck_equals(o._listeners.length, 2);
-xcheck_equals(o._listeners.spliceCalled, true);
+// Gnash fails as it gives up if _listeners isn't an array
+check_equals(o._listeners.pushCalled, true);
+check_equals(o._listeners.length, 2);
+check_equals(o._listeners.spliceCalled, true);
 
 
 //--------------------------------
@@ -155,69 +160,69 @@
 b = new Object; b.name = 'b'; b.onTest = onTest;
 
 ret = bcast.addListener(a);
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 ret = bcast.addListener(b);
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 //note("Broadcasting");
 ret = bcast.broadcastMessage('onTest');
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(a.order, 1);
-xcheck_equals(b.order, 2);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(a.order, 1);
+check_equals(b.order, 2);
 
 ret = bcast.addListener(b); // b is not added again
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 //note("Broadcasting");
 bcast.broadcastMessage('onTest');
-xcheck_equals(a.order, 3);
-xcheck_equals(b.order, 4);
+check_equals(a.order, 3);
+check_equals(b.order, 4);
 
 ret = bcast.addListener(a); // listener a is moved from first to last position 
to _listeners
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 //note("Broadcasting");
 bcast.broadcastMessage('onTest');
-xcheck_equals(b.order, 5);
-xcheck_equals(a.order, 6);
+check_equals(b.order, 5);
+check_equals(a.order, 6);
 
 bcast._listeners.push(a); // force double a listener
 //note("Broadcasting");
 bcast.broadcastMessage('onTest');
-xcheck_equals(b.order, 7);
-xcheck_equals(a.order, 9); // a.order was set twice
+check_equals(b.order, 7);
+check_equals(a.order, 9); // a.order was set twice
 
 bcast.addListener(a); // first a is moved from first to last position to 
_listeners
 //note("Broadcasting");
 ret = bcast.broadcastMessage('onTest');
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(b.order, 10);
-xcheck_equals(a.order, 12); // a is still set twice
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(b.order, 10);
+check_equals(a.order, 12); // a is still set twice
 
 bcast._listeners.push(b); // force double b, order should now be: b,a,a,b
 //note("Broadcasting");
 bcast.broadcastMessage('onTest');
-xcheck_equals(b.order, 16); 
-xcheck_equals(a.order, 15); 
+check_equals(b.order, 16); 
+check_equals(a.order, 15); 
 
 ret = bcast.addListener(b); // *first* b is removed, another one added, new 
order is a,a,b,b
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
 //note("Broadcasting");
 bcast.broadcastMessage('onTest');
-xcheck_equals(a.order, 18); 
-xcheck_equals(b.order, 20);
+check_equals(a.order, 18); 
+check_equals(b.order, 20);
 
 ret = bcast.removeListener(b); // only first is removed
-xcheck_equals(typeof(ret), 'boolean');
-xcheck_equals(ret, true);
-xcheck_equals(bcast._listeners.length, 3); // expect: a,a,b
+check_equals(typeof(ret), 'boolean');
+check_equals(ret, true);
+check_equals(bcast._listeners.length, 3); // expect: a,a,b
 bcast.broadcastMessage('onTest');
-xcheck_equals(a.order, 22); 
-xcheck_equals(b.order, 23);
+check_equals(a.order, 22); 
+check_equals(b.order, 23);
 
 // TODO: test broadcastMessage with additional arguments
 //       and effects of overriding Function.apply

Index: server/asobj/AsBroadcaster.cpp
===================================================================
RCS file: server/asobj/AsBroadcaster.cpp
diff -N server/asobj/AsBroadcaster.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/asobj/AsBroadcaster.cpp      11 Sep 2007 17:01:23 -0000      1.1
@@ -0,0 +1,369 @@
+// AsBroadcaster.cpp - AsBroadcaster AS interface
+// 
+//   Copyright (C) 2005, 2006, 2007 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 3 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "array.h" // for _listeners construction
+#include "log.h"
+#include "AsBroadcaster.h"
+#include "fn_call.h"
+#include "builtin_function.h"
+#include "VM.h" // for getPlayerVersion() 
+#include "Object.h" // for getObjectInterface
+
+#include <boost/algorithm/string/case_conv.hpp> // for PROPNAME
+
+namespace gnash {
+
+class BroadcasterVisitor
+{
+       
+       /// Name of the event being broadcasted
+       /// appropriately cased based on SWF version
+       /// of the current VM
+       std::string _eventName;
+
+       /// Environment to use for marhalling and functions invokation
+       as_environment& _env;
+
+       // These two will be needed for consistency checking
+       //size_t _origEnvStackSize;
+       //size_t _origEnvCallStackSize;
+
+public:
+
+       /// @param eName name of event, will be converted to lowercase if needed
+       ///
+       /// @param env Environment to use for marhalling and functions 
invocation.
+       ///        Note that visit() will push values on it !
+       ///
+       BroadcasterVisitor(const std::string& eName, as_environment& env)
+               :
+               _eventName(PROPNAME(eName)),
+               _env(env)
+       {
+       }
+
+       /// Call a method on the given value
+       void visit(as_value& v)
+       {
+               boost::intrusive_ptr<as_object> o = v.to_object();
+               if ( ! o ) return;
+
+#ifndef NDEBUG
+               size_t oldStackSize = _env.stack_size();
+#endif
+               /*as_value ret =*/ o->callMethod(_eventName, _env);
+               assert ( _env.stack_size() == oldStackSize );
+       }
+};
+
+void 
+AsBroadcaster::initialize(as_object& o)
+{
+       log_debug("Initializing object %p as an AsBroadcaster", (void*)&o);
+       // TODO: reserch on protection flags for these methods
+       o.set_member(PROPNAME("addListener"), new 
builtin_function(AsBroadcaster::addListener_method));
+       o.set_member(PROPNAME("removeListener"), new 
builtin_function(AsBroadcaster::removeListener_method));
+       o.set_member(PROPNAME("broadcastMessage"), new 
builtin_function(AsBroadcaster::broadcastMessage_method));
+       o.set_member("_listeners", new as_array_object());
+
+#ifndef NDEBUG
+       as_value tmp;
+       assert(o.get_member("_listeners", &tmp));
+       assert(tmp.is_object());
+       assert(o.get_member(PROPNAME("addListener"), &tmp));
+       assert(tmp.is_function());
+       assert(o.get_member(PROPNAME("removeListener"), &tmp));
+       assert(tmp.is_function());
+       assert(o.get_member(PROPNAME("broadcastMessage"), &tmp));
+       assert(tmp.is_function());
+#endif
+}
+
+as_value
+AsBroadcaster::initialize_method(const fn_call& fn)
+{
+       // TODO: initialize first arg object as an AsBroadcaster
+       //       (call the AsBroadcaster::initialize(as_object*) static ?)
+       if ( fn.nargs < 1 )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("AsBroadcaster.initialize() requires one 
argument, none given"));
+               );
+               return as_value();
+       }
+
+       // TODO: check if automatic primitive to object conversion apply here
+       as_value& tgtval = fn.arg(0);
+       if ( ! tgtval.is_object() )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("AsBroadcaster.initialize(%s): first arg is not 
an object"), tgtval.to_debug_string().c_str()); 
+               );
+               return as_value();
+       }
+
+       boost::intrusive_ptr<as_object> tgt = tgtval.to_object();
+
+       AsBroadcaster::initialize(*tgt);
+
+       log_debug("AsBroadcaster.initialize(%s): TESTING", 
tgtval.to_debug_string().c_str());
+
+       return as_value();
+}
+
+as_value
+AsBroadcaster::addListener_method(const fn_call& fn)
+{
+       boost::intrusive_ptr<as_object> obj = fn.this_ptr;
+
+       as_value newListener; assert(newListener.is_undefined());
+       if ( fn.nargs ) newListener = fn.arg(0);
+
+       obj->callMethod(PROPNAME("removeListener"), fn.env(), newListener);
+
+       as_value listenersValue;
+
+       // TODO: test if we're supposed to crawl the target object's 
+       //       inheritance chain in case it's own property _listeners 
+       //       has been deleted while another one is found in any base
+       //       class.
+       if ( ! obj->get_member("_listeners", &listenersValue) )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object has no 
_listeners member"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str());
+               );
+               return as_value(true); // odd, but seems the case..
+       }
+
+       // assuming no automatic primitive-to-object cast will return an 
array...
+       if ( ! listenersValue.is_object() )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an object: %s"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+               return as_value(false); // TODO: check this
+       }
+
+       boost::intrusive_ptr<as_object> listenersObj = 
listenersValue.to_object();
+       assert(listenersObj);
+
+       boost::intrusive_ptr<as_array_object> listeners = 
boost::dynamic_pointer_cast<as_array_object>(listenersObj);
+       if ( ! listeners )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an array: %s -- will call 'push' on it anyway"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+
+               listenersObj->callMethod(PROPNAME("push"), fn.env(), 
newListener);
+
+       }
+       else
+       {
+               listeners->push(newListener);
+       }
+
+       log_debug("%p.addListener(%s) TESTING", (void*)fn.this_ptr.get(), 
fn.dump_args().c_str());
+       return as_value(true);
+
+}
+
+as_value
+AsBroadcaster::removeListener_method(const fn_call& fn)
+{
+       boost::intrusive_ptr<as_object> obj = fn.this_ptr;
+
+       as_value listenersValue;
+
+       // TODO: test if we're supposed to crawl the target object's 
+       //       inheritance chain in case it's own property _listeners 
+       //       has been deleted while another one is found in any base
+       //       class.
+       if ( ! obj->get_member("_listeners", &listenersValue) )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object has no 
_listeners member"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str());
+               );
+               return as_value(false); // TODO: check this
+       }
+
+       // assuming no automatic primitive-to-object cast will return an 
array...
+       if ( ! listenersValue.is_object() )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an object: %s"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+               return as_value(false); // TODO: check this
+       }
+
+       boost::intrusive_ptr<as_object> listenersObj = 
listenersValue.to_object();
+       assert(listenersObj);
+
+       as_value listenerToRemove; assert(listenerToRemove.is_undefined());
+       if ( fn.nargs ) listenerToRemove = fn.arg(0);
+
+       boost::intrusive_ptr<as_array_object> listeners = 
boost::dynamic_pointer_cast<as_array_object>(listenersObj);
+       if ( ! listeners )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an array: %s"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+
+               // TODO: implement brute force scan of pseudo-array
+               unsigned int length = 
listenersObj->getMember("length").to_int(fn.env());
+               for (unsigned int i=0; i<length; ++i)
+               {
+                       as_value iVal(i);
+                       std::string n = iVal.to_string(&(fn.env()));
+                       as_value v = listenersObj->getMember(n);
+                       if ( v.equals(listenerToRemove, fn.env()) )
+                       {
+                               listenersObj->callMethod("splice", fn.env(), 
iVal, as_value(1));
+                               return as_value(true); 
+                       }
+               }
+
+               return as_value(false); // TODO: check this
+       }
+       else
+       {
+               // Remove the first listener matching the new value
+               // See 
http://www.senocular.com/flash/tutorials/listenersasbroadcaster/?page=2
+               // TODO: make this call as a normal (don't want to rely on 
_listeners type at all)
+               bool removed = listeners->removeFirst(listenerToRemove, 
fn.env());
+               return as_value(removed);
+       }
+
+}
+
+as_value
+AsBroadcaster::broadcastMessage_method(const fn_call& fn)
+{
+       boost::intrusive_ptr<as_object> obj = fn.this_ptr;
+
+       as_value listenersValue;
+
+       // TODO: test if we're supposed to crawl the target object's 
+       //       inheritance chain in case it's own property _listeners 
+       //       has been deleted while another one is found in any base
+       //       class.
+       if ( ! obj->get_member("_listeners", &listenersValue) )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object has no 
_listeners member"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str());
+               );
+               return as_value(); // TODO: check this
+       }
+
+       // assuming no automatic primitive-to-object cast will return an 
array...
+       if ( ! listenersValue.is_object() )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an object: %s"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+               return as_value(); // TODO: check this
+       }
+
+       boost::intrusive_ptr<as_array_object> listeners = 
boost::dynamic_pointer_cast<as_array_object>(listenersValue.to_object());
+       if ( ! listeners )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror(_("%p.addListener(%s): this object's _listener 
isn't an array: %s"),
+                       (void*)fn.this_ptr.get(),
+                       fn.dump_args().c_str(), 
listenersValue.to_debug_string().c_str());
+               );
+               return as_value(); // TODO: check this
+       }
+
+       if ( ! fn.nargs )
+       {
+               IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror("%p.broadcastMessage() needs an argument", 
(void*)fn.this_ptr.get());
+               );
+               return as_value();
+       }
+
+       BroadcasterVisitor visitor(fn.arg(0).to_string(), fn.env());
+       listeners->visitAll(visitor);
+
+       log_debug("AsBroadcaster.broadcastMessage TESTING");
+
+       return as_value(true);
+}
+
+static as_object*
+getAsBroadcasterInterface()
+{
+       static boost::intrusive_ptr<as_object> o=NULL;
+       if ( o == NULL )
+       {
+               o = new as_object(getObjectInterface());
+               VM::get().addStatic(o.get());
+       }
+       return o.get();
+}
+
+static as_value
+AsBroadcaster_ctor(const fn_call& /*fn*/)
+{
+       as_object* obj = new as_object(getAsBroadcasterInterface());
+       return as_value(obj); // will keep alive
+}
+
+void
+AsBroadcaster_init(as_object& global)
+{
+       // _global.AsBroadcaster is NOT a class, but a simple object
+
+       VM& vm = VM::get();
+       int swfVersion = vm.getSWFVersion();
+
+       static boost::intrusive_ptr<as_object> obj = NULL;
+       if ( ! obj )
+       {
+               obj = new builtin_function(AsBroadcaster_ctor, 
getAsBroadcasterInterface()); 
+               VM::get().addStatic(obj.get()); // correct ?
+               if ( swfVersion >= 6 )
+               {
+                       obj->init_member("initialize", new 
builtin_function(AsBroadcaster::initialize_method));
+               }
+       }
+       global.init_member("AsBroadcaster", obj.get());
+}
+
+} // end of gnash namespace

Index: server/asobj/AsBroadcaster.h
===================================================================
RCS file: server/asobj/AsBroadcaster.h
diff -N server/asobj/AsBroadcaster.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/asobj/AsBroadcaster.h        11 Sep 2007 17:01:23 -0000      1.1
@@ -0,0 +1,74 @@
+// 
+//   Copyright (C) 2005, 2006, 2007 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 3 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
+
+// 
+//
+//
+
+#ifndef __ASBROADCASTER_H__
+#define __ASBROADCASTER_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// Forward declarations
+namespace gnash {
+       class as_value;
+       class as_object;
+       class fn_call;
+}
+
+namespace gnash {
+  
+/// AsBroadcaster facilities
+class AsBroadcaster {
+
+public:
+
+       /// Initialize the given object as an AsBroadcaster
+       //
+       /// This method set the addListener,removeListener and broadcastMessage
+       /// AS methods with the object, and set the _listners array member.
+       ///
+       /// It is exposed so that Stage,TextField,Key,Mouse and Selection
+       /// can call this internally.
+       ///
+       /// The AsBroadcaster_init will take care of registering
+       /// the _global.AsBroadcaster object and it's 'initialize'
+       /// method for user-defined broadcasters initialization
+       ///
+       static void initialize(as_object& obj);
+
+       /// AsBroadcaster.initialize() AS method
+       static as_value initialize_method(const fn_call& fn);
+
+private:
+
+       static as_value addListener_method(const fn_call& fn);
+       static as_value removeListener_method(const fn_call& fn);
+       static as_value broadcastMessage_method(const fn_call& fn);
+
+};
+
+void AsBroadcaster_init(as_object& global);
+
+} // end of gnash namespace
+
+// __ASBROADCASTER_H__
+#endif
+




reply via email to

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