drop libxv, add lsb-release
[gnash.git] / libcore / as_function.cpp
blob2d311d0aa92d94b311e146bc21f536621a1dbf3a
1 // as_function.cpp: ActionScript Functions, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 //
21 #include "smart_ptr.h" // GNASH_USE_GC
22 #include "log.h"
23 #include "as_function.h"
24 #include "as_value.h"
25 #include "Array_as.h"
26 #include "Global_as.h"
27 #include "fn_call.h"
28 #include "GnashException.h"
29 #include "VM.h"
30 #include "namedStrings.h"
31 #include "NativeFunction.h"
32 #include "Object.h"
33 #include "DisplayObject.h"
35 #include <iostream>
37 namespace gnash {
39 // Forward declarations
40 namespace {
41 as_value function_apply(const fn_call& fn);
42 as_value function_call(const fn_call& fn);
43 as_value function_ctor(const fn_call& fn);
46 as_function::as_function(Global_as& gl)
48 as_object(gl)
52 std::string
53 as_function::stringValue() const
55 return "[type Function]";
58 as_object*
59 constructInstance(as_function& ctor, const as_environment& env,
60 fn_call::Args& args)
62 Global_as& gl = getGlobal(ctor);
64 // Create an empty object, with a ref to the constructor's prototype.
65 // The function's prototype property always becomes the new object's
66 // __proto__ member, regardless of whether it is an object and regardless
67 // of its visibility.
68 as_object* newobj = new as_object(gl);
69 Property* proto = ctor.getOwnProperty(NSV::PROP_PROTOTYPE);
70 if (proto) newobj->set_prototype(proto->getValue(ctor));
72 return ctor.construct(*newobj, env, args);
75 as_object*
76 as_function::construct(as_object& newobj, const as_environment& env,
77 fn_call::Args& args)
79 const int swfversion = getSWFVersion(env);
81 // Add a __constructor__ member to the new object visible from version 6.
82 const int flags = PropFlags::dontEnum |
83 PropFlags::onlySWF6Up;
85 newobj.init_member(NSV::PROP_uuCONSTRUCTORuu, this, flags);
87 if (swfversion < 7) {
88 newobj.init_member(NSV::PROP_CONSTRUCTOR, this, PropFlags::dontEnum);
91 // Don't set a super so that it will be constructed only if required
92 // by the function.
93 fn_call fn(&newobj, env, args, 0, true);
94 as_value ret;
96 try {
97 ret = call(fn);
99 catch (GnashException& ex) {
100 // Catching a std::exception here can mask all sorts of bad
101 // behaviour, as (for instance) a poorly constructed string may
102 // smash the stack, throw an exception, but not abort.
103 // This is very effective at confusing debugging tools.
104 // We only throw GnashExceptions. A std::bad_alloc may also be
105 // reasonable, but anything else shouldn't be caught here.
106 log_debug("Native function called as constructor threw exception: "
107 "%s", ex.what());
109 // If a constructor throws an exception, throw it back to the
110 // caller. This is the only way to signal that a constructor
111 // did not return anything.
112 throw;
115 // Some built-in constructors do things properly and operate on the
116 // 'this' pointer. Others return a new object. This is to handle those
117 // cases.
118 if (isBuiltin() && ret.is_object()) {
119 as_object* fakeobj = toObject(ret, getVM(env));
121 fakeobj->init_member(NSV::PROP_uuCONSTRUCTORuu, as_value(this),
122 flags);
124 // Also for SWF5+ only?
125 if (swfversion < 7) {
126 fakeobj->init_member(NSV::PROP_CONSTRUCTOR, as_value(this),
127 PropFlags::dontEnum);
129 return fakeobj;
132 return &newobj;
136 void
137 registerFunctionNative(as_object& global)
139 VM& vm = getVM(global);
140 vm.registerNative(function_call, 101, 10);
141 vm.registerNative(function_apply, 101, 11);
144 void
145 function_class_init(as_object& where, const ObjectURI& uri)
147 Global_as& gl = getGlobal(where);
149 NativeFunction* func = new NativeFunction(gl, function_ctor);
150 as_object* proto = createObject(gl);
152 func->init_member(NSV::PROP_PROTOTYPE, proto);
153 func->init_member(NSV::PROP_CONSTRUCTOR, func);
154 proto->init_member(NSV::PROP_CONSTRUCTOR, func);
156 // Register _global.Function, only visible for SWF6 up
157 const int swf6flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
158 func->init_member(NSV::PROP_uuPROTOuu, proto, swf6flags);
159 where.init_member(uri, func, swf6flags);
161 VM& vm = getVM(where);
163 // Note: these are the first functions created, and they need the
164 // Function class to be registered.
165 proto->init_member("call", vm.getNative(101, 10), swf6flags);
166 proto->init_member("apply", vm.getNative(101, 11), swf6flags);
169 namespace {
171 as_value
172 function_ctor(const fn_call& /*fn*/)
174 return as_value();
178 class PushFunctionArgs
180 public:
181 PushFunctionArgs(fn_call& fn) : _fn(fn) {}
182 void operator()(const as_value& val) {
183 _fn.pushArg(val);
185 private:
186 fn_call& _fn;
189 as_value
190 function_apply(const fn_call& fn)
193 as_object* function_obj = ensure<ValidThis>(fn);
195 // Copy new function call from old one, we'll modify
196 // the copy only if needed
197 fn_call new_fn_call(fn);
198 new_fn_call.resetArgs();
200 if (!fn.nargs)
202 IF_VERBOSE_ASCODING_ERRORS(
203 log_aserror (_("Function.apply() called with no args"));
205 new_fn_call.this_ptr = new as_object(getGlobal(fn));
207 else
209 // Get the object to use as 'this' reference
210 as_object* obj = toObject(fn.arg(0), getVM(fn));
212 if (!obj) obj = new as_object(getGlobal(fn));
214 new_fn_call.this_ptr = obj;
216 // Note: do not override fn_call::super by creating a super
217 // object, as it may not be needed. Doing so can have a very
218 // detrimental effect on memory usage!
219 // Normal supers will be created when needed in the function
220 // call.
221 new_fn_call.super = 0;
223 // Check for second argument ('arguments' array)
224 if (fn.nargs > 1)
226 IF_VERBOSE_ASCODING_ERRORS(
227 if (fn.nargs > 2) {
228 log_aserror(_("Function.apply() got %d"
229 " args, expected at most 2"
230 " -- discarding the ones in"
231 " excess"),
232 fn.nargs);
236 boost::intrusive_ptr<as_object> arg1 =
237 toObject(fn.arg(1), getVM(fn));
239 if (arg1) {
240 PushFunctionArgs pa(new_fn_call);
241 foreachArray(*arg1, pa);
246 // Call the function
247 as_value rv = function_obj->call(new_fn_call);
249 return rv;
252 as_value
253 function_call(const fn_call& fn)
256 as_object* function_obj = ensure<ValidThis>(fn);
258 // Copy new function call from old one, we'll modify
259 // the copy only if needed
260 fn_call new_fn_call(fn);
262 as_object* tp;
264 if (!fn.nargs || fn.arg(0).is_undefined() || fn.arg(0).is_null()) {
265 tp = new as_object(getGlobal(fn));
267 else tp = toObject(fn.arg(0), getVM(fn));
269 new_fn_call.this_ptr = tp;
270 new_fn_call.super = 0;
271 if (fn.nargs) new_fn_call.drop_bottom();
273 // Call the function
274 return function_obj->call(new_fn_call);
278 } // anonymous namespace
279 } // gnash namespace