~ubuntu-branches/ubuntu/karmic/gnash/karmic

« back to all changes in this revision

Viewing changes to server/asobj/Object.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Object.cpp:  Implementation of ActionScript Object class, for Gnash.
2
 
// 
3
 
//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
 
// 
5
 
// This program is free software; you can redistribute it and/or modify
6
 
// it under the terms of the GNU General Public License as published by
7
 
// the Free Software Foundation; either version 3 of the License, or
8
 
// (at your option) any later version.
9
 
// 
10
 
// This program is distributed in the hope that it will be useful,
11
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
// GNU General Public License for more details.
14
 
//
15
 
// You should have received a copy of the GNU General Public License
16
 
// along with this program; if not, write to the Free Software
17
 
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
//
19
 
 
20
 
/* $Id: Object.cpp,v 1.41 2008/02/19 19:20:55 bwy Exp $ */
21
 
 
22
 
#include "tu_config.h"
23
 
#include "Object.h"
24
 
#include "smart_ptr.h"
25
 
#include "fn_call.h"
26
 
#include "as_object.h" // for inheritance
27
 
#include "builtin_function.h" // need builtin_function
28
 
#include "movie_definition.h" // for Object.registerClass (get_exported_resource)
29
 
//#include "character.h" // for Object.registerClass  (get_root_movie)
30
 
#include "sprite_instance.h" // for Object.registerClass  (get_movie_definition)
31
 
#include "sprite_definition.h" // for Object.registerClass  (get_movie_definition)
32
 
#include "VM.h" // for SWF version (attachObjectInterface)
33
 
 
34
 
#include "log.h"
35
 
 
36
 
#include <string>
37
 
#include <sstream>
38
 
 
39
 
namespace gnash {
40
 
 
41
 
// Forward declarations
42
 
static as_value object_addproperty(const fn_call&);
43
 
static as_value object_registerClass(const fn_call& fn);
44
 
static as_value object_hasOwnProperty(const fn_call&);
45
 
static as_value object_isPropertyEnumerable(const fn_call&);
46
 
static as_value object_isPrototypeOf(const fn_call&);
47
 
static as_value object_watch(const fn_call&);
48
 
static as_value object_unwatch(const fn_call&);
49
 
 
50
 
 
51
 
static void
52
 
attachObjectInterface(as_object& o)
53
 
{
54
 
        VM& vm = o.getVM();
55
 
        int target_version = vm.getSWFVersion();
56
 
 
57
 
        // Object.valueOf()
58
 
        vm.registerNative(as_object::valueof_method, 101, 3);
59
 
        o.init_member("valueOf", vm.getNative(101, 3));
60
 
 
61
 
        // Object.toString()
62
 
        vm.registerNative(as_object::tostring_method, 101, 4);
63
 
        o.init_member("toString", vm.getNative(101, 4));
64
 
 
65
 
        if ( target_version  < 6 ) return;
66
 
 
67
 
        // Object.addProperty()
68
 
        vm.registerNative(object_addproperty, 101, 2);
69
 
        o.init_member("addProperty", vm.getNative(101, 2));
70
 
 
71
 
        // Object.hasOwnProperty()
72
 
        vm.registerNative(object_hasOwnProperty, 101, 5);
73
 
        o.init_member("hasOwnProperty", vm.getNative(101, 5));
74
 
 
75
 
        // Object.isPropertyEnumerable()
76
 
        vm.registerNative(object_isPropertyEnumerable, 101, 7);
77
 
        o.init_member("isPropertyEnumerable", vm.getNative(101, 7));
78
 
 
79
 
        // Object.isPrototypeOf()
80
 
        vm.registerNative(object_isPrototypeOf, 101, 6);
81
 
        o.init_member("isPrototypeOf", vm.getNative(101, 6));
82
 
 
83
 
        // Object.watch()
84
 
        vm.registerNative(object_watch, 101, 0);
85
 
        o.init_member("watch", vm.getNative(101, 0));
86
 
 
87
 
        // Object.unwatch()
88
 
        vm.registerNative(object_unwatch, 101, 1);
89
 
        o.init_member("unwatch", vm.getNative(101, 1));
90
 
}
91
 
 
92
 
as_object*
93
 
getObjectInterface()
94
 
{
95
 
        static boost::intrusive_ptr<as_object> o;
96
 
        if ( o == NULL )
97
 
        {
98
 
                o = new as_object(); // end of the inheritance chain
99
 
                attachObjectInterface(*o);
100
 
                //o->set_prototype(o.get()); // proto is self ?
101
 
        }
102
 
        return o.get();
103
 
}
104
 
 
105
 
// FIXME: add some useful methods :)
106
 
class object_as_object : public as_object
107
 
{
108
 
 
109
 
public:
110
 
 
111
 
        object_as_object()
112
 
                :
113
 
                as_object(getObjectInterface())
114
 
        {
115
 
        }
116
 
 
117
 
};
118
 
 
119
 
static as_value
120
 
object_ctor(const fn_call& fn)
121
 
    // Constructor for ActionScript class Object.
122
 
{
123
 
        if ( fn.nargs == 1 ) // copy constructor
124
 
        {
125
 
                // just copy the reference
126
 
                //
127
 
                // WARNING: it is likely that fn.result and fn.arg(0)
128
 
                // are the same location... so we might skip
129
 
                // the set_as_object() call as a whole.
130
 
                return as_value(fn.arg(0).to_object());
131
 
        }
132
 
 
133
 
        boost::intrusive_ptr<as_object> new_obj;
134
 
        if ( fn.nargs == 0 )
135
 
        {
136
 
                new_obj = new object_as_object();
137
 
        }
138
 
        else
139
 
        {
140
 
                IF_VERBOSE_ASCODING_ERRORS (
141
 
                log_aserror(_("Too many args to Object constructor"));
142
 
                )
143
 
                new_obj = new object_as_object();
144
 
        }
145
 
 
146
 
        return as_value(new_obj.get()); // will keep alive
147
 
}
148
 
 
149
 
std::auto_ptr<as_object>
150
 
init_object_instance()
151
 
{
152
 
        return std::auto_ptr<as_object>(new object_as_object);
153
 
}
154
 
 
155
 
 
156
 
// extern (used by Global.cpp)
157
 
void object_class_init(as_object& global)
158
 
{
159
 
        // This is going to be the global Object "class"/"function"
160
 
        static boost::intrusive_ptr<builtin_function> cl=NULL;
161
 
 
162
 
        VM& vm = VM::get();
163
 
 
164
 
        if ( cl == NULL )
165
 
        {
166
 
                cl=new builtin_function(&object_ctor, getObjectInterface());
167
 
 
168
 
                // TODO: is this needed ?
169
 
                //cl->init_member("prototype", as_value(getObjectInterface()));
170
 
 
171
 
                // Object.registerClass() -- TODO: should this only be in SWF6 or higher ?
172
 
                vm.registerNative(object_registerClass, 101, 8);
173
 
                cl->init_member("registerClass", vm.getNative(101, 8));
174
 
 
175
 
                     
176
 
        }
177
 
 
178
 
        // Register _global.Object
179
 
        global.init_member("Object", cl.get());
180
 
 
181
 
}
182
 
 
183
 
static as_value
184
 
object_addproperty(const fn_call& fn)
185
 
{
186
 
        assert(fn.this_ptr);
187
 
        boost::intrusive_ptr<as_object> obj = fn.this_ptr;
188
 
 
189
 
        if ( fn.nargs != 3 )
190
 
        {
191
 
                IF_VERBOSE_ASCODING_ERRORS(
192
 
                std::stringstream ss;
193
 
                fn.dump_args(ss);
194
 
                log_aserror(_("Invalid call to Object.addProperty(%s) - "
195
 
                        "expected 3 arguments (<name>, <getter>, <setter>)"),
196
 
                        ss.str().c_str());
197
 
                );
198
 
 
199
 
                // if we've been given more args then needed there's
200
 
                // no need to abort here
201
 
                if ( fn.nargs < 3 )
202
 
                {
203
 
                        return as_value(false);
204
 
                }
205
 
        }
206
 
 
207
 
        const std::string& propname = fn.arg(0).to_string();
208
 
        if ( propname.empty() )
209
 
        {
210
 
                IF_VERBOSE_ASCODING_ERRORS(
211
 
                log_aserror(_("Invalid call to Object.addProperty() - "
212
 
                        "empty property name"));
213
 
                );
214
 
                return as_value(false);
215
 
        }
216
 
 
217
 
        as_function* getter = fn.arg(1).to_as_function();
218
 
        if ( ! getter )
219
 
        {
220
 
                IF_VERBOSE_ASCODING_ERRORS(
221
 
                log_aserror(_("Invalid call to Object.addProperty() - "
222
 
                        "getter is not an AS function"));
223
 
                );
224
 
                return as_value(false);
225
 
        }
226
 
 
227
 
        as_function* setter = fn.arg(2).to_as_function();
228
 
        if ( ! setter )
229
 
        {
230
 
                IF_VERBOSE_ASCODING_ERRORS(
231
 
                log_aserror(_("Invalid call to Object.addProperty() - "
232
 
                        "setter is not an AS function"));
233
 
                );
234
 
                return as_value(false);
235
 
        }
236
 
 
237
 
 
238
 
        // Now that we checked everything, let's call the as_object
239
 
        // interface for getter/setter properties :)
240
 
        
241
 
        bool result = obj->add_property(propname, *getter, *setter);
242
 
 
243
 
        //log_debug("Object.addProperty(): testing");
244
 
        return as_value(result);
245
 
}
246
 
 
247
 
static as_value
248
 
object_registerClass(const fn_call& fn)
249
 
{
250
 
        assert(fn.this_ptr);
251
 
        //as_object* obj = fn.this_ptr;
252
 
 
253
 
        if ( fn.nargs != 2 )
254
 
        {
255
 
                IF_VERBOSE_ASCODING_ERRORS(
256
 
                std::stringstream ss;
257
 
                fn.dump_args(ss);
258
 
                log_aserror(_("Invalid call to Object.registerClass(%s) - "
259
 
                        "expected 2 arguments (<symbol>, <constructor>)"),
260
 
                        ss.str().c_str());
261
 
                );
262
 
 
263
 
                // if we've been given more args then needed there's
264
 
                // no need to abort here
265
 
                if ( fn.nargs < 2 )
266
 
                {
267
 
                        return as_value(false);
268
 
                }
269
 
        }
270
 
 
271
 
        const std::string& symbolid = fn.arg(0).to_string();
272
 
        if ( symbolid.empty() )
273
 
        {
274
 
                IF_VERBOSE_ASCODING_ERRORS(
275
 
                std::stringstream ss;
276
 
                fn.dump_args(ss);
277
 
                log_aserror(_("Invalid call to Object.registerClass(%s) - "
278
 
                        "first argument (symbol id) evaluates to empty string"), ss.str().c_str());
279
 
                );
280
 
                return as_value(false);
281
 
        }
282
 
 
283
 
        as_function* theclass = fn.arg(1).to_as_function();
284
 
        if ( ! theclass )
285
 
        {
286
 
                IF_VERBOSE_ASCODING_ERRORS(
287
 
                std::stringstream ss;
288
 
                fn.dump_args(ss);
289
 
                log_aserror(_("Invalid call to Object.registerClass(%s) - "
290
 
                        "second argument (class) is not a function)"), ss.str().c_str());
291
 
                );
292
 
                return as_value(false);
293
 
        }
294
 
 
295
 
        // Find the exported resource
296
 
 
297
 
        // TODO: check to *which* definition should we ask the export
298
 
        //       this code uses the *relative* root of current environment's target
299
 
        movie_definition* def = VM::get().getRoot().get_movie_definition();
300
 
        boost::intrusive_ptr<resource> exp_res = def->get_exported_resource(symbolid.c_str());
301
 
        if ( ! exp_res )
302
 
        {
303
 
                IF_VERBOSE_ASCODING_ERRORS(
304
 
                log_aserror(_("Object.registerClass(%s, %s): "
305
 
                        "can't find exported symbol"),
306
 
                        symbolid.c_str(), 
307
 
                        typeid(theclass).name());
308
 
                );
309
 
                return as_value(false);
310
 
        }
311
 
 
312
 
        // Check that the exported resource is a sprite_definition
313
 
        // (we're looking for a MovieClip symbol)
314
 
 
315
 
        boost::intrusive_ptr<sprite_definition> exp_clipdef = 
316
 
                boost::intrusive_ptr<sprite_definition>(dynamic_cast<sprite_definition*>(exp_res.get()));
317
 
 
318
 
 
319
 
        if ( ! exp_clipdef )
320
 
        {
321
 
                IF_VERBOSE_ASCODING_ERRORS(
322
 
                log_aserror(_("Object.registerClass(%s, %s): "
323
 
                        "exported symbol is not a MovieClip symbol "
324
 
                        "(sprite_definition), but a %s"),
325
 
                        symbolid.c_str(), 
326
 
                        typeid(theclass).name(),
327
 
                        typeid(*exp_res).name());
328
 
                );
329
 
                return as_value(false);
330
 
        }
331
 
 
332
 
        exp_clipdef->registerClass(theclass);
333
 
        return as_value(true);
334
 
}
335
 
 
336
 
as_value
337
 
object_hasOwnProperty(const fn_call& fn)
338
 
{
339
 
        //assert(fn.result->is_undefined());
340
 
        if ( fn.nargs < 1 )
341
 
        {
342
 
                IF_VERBOSE_ASCODING_ERRORS(
343
 
                log_aserror(_("Object.hasOwnProperty() requires one arg"));
344
 
                );
345
 
                return as_value(false);
346
 
        }
347
 
        as_value& arg = fn.arg(0);
348
 
        const std::string& propname = arg.to_string();
349
 
        if ( arg.is_undefined() || propname.empty() )
350
 
        {
351
 
                IF_VERBOSE_ASCODING_ERRORS(
352
 
                log_aserror(_("Invalid call to Object.hasOwnProperty('%s')"), arg.to_debug_string().c_str());
353
 
                );
354
 
                return as_value(false);
355
 
        }
356
 
        return as_value(fn.this_ptr->getOwnProperty(VM::get().getStringTable().find(propname)) != NULL);
357
 
}
358
 
 
359
 
as_value
360
 
object_isPropertyEnumerable(const fn_call& fn)
361
 
{
362
 
        //assert(fn.result->is_undefined());
363
 
        if ( fn.nargs < 1 )
364
 
        {
365
 
                IF_VERBOSE_ASCODING_ERRORS(
366
 
                log_aserror(_("Object.isPropertyEnumerable() requires one arg"));
367
 
                );
368
 
                return as_value();
369
 
        }
370
 
        as_value& arg = fn.arg(0);
371
 
        const std::string& propname = arg.to_string();
372
 
        if ( arg.is_undefined() || propname.empty() )
373
 
        {
374
 
                IF_VERBOSE_ASCODING_ERRORS(
375
 
                log_aserror(_("Invalid call to Object.isPropertyEnumerable('%s')"), arg.to_debug_string().c_str());
376
 
                );
377
 
                return as_value();
378
 
        }
379
 
 
380
 
        Property* prop = fn.this_ptr->getOwnProperty(VM::get().getStringTable().find(propname));
381
 
        if ( ! prop )
382
 
        {
383
 
                return as_value(false);
384
 
        }
385
 
 
386
 
        return as_value( ! prop->getFlags().get_dont_enum() );
387
 
}
388
 
 
389
 
as_value
390
 
object_isPrototypeOf(const fn_call& fn)
391
 
{
392
 
        //assert(fn.result->is_undefined());
393
 
        if ( fn.nargs < 1 )
394
 
        {
395
 
                IF_VERBOSE_ASCODING_ERRORS(
396
 
                log_aserror(_("Object.isPrototypeOf() requires one arg"));
397
 
                );
398
 
                return as_value(false); 
399
 
        }
400
 
 
401
 
        boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
402
 
        if ( ! obj )
403
 
        {
404
 
                IF_VERBOSE_ASCODING_ERRORS(
405
 
                log_aserror(_("First arg to Object.isPrototypeOf(%s) is not an object"), fn.arg(0).to_debug_string().c_str());
406
 
                );
407
 
                return as_value(false);
408
 
        }
409
 
 
410
 
        return as_value(fn.this_ptr->prototypeOf(*obj));
411
 
 
412
 
}
413
 
 
414
 
as_value
415
 
object_watch(const fn_call&)
416
 
{
417
 
        static bool warned = false;
418
 
        if ( ! warned ) {
419
 
                log_unimpl (__FUNCTION__);
420
 
                warned=true;
421
 
        }
422
 
        return as_value();
423
 
}
424
 
 
425
 
as_value
426
 
object_unwatch(const fn_call&)
427
 
{
428
 
        static bool warned = false;
429
 
        if ( ! warned ) {
430
 
                log_unimpl (__FUNCTION__);
431
 
                warned=true;
432
 
        }
433
 
        return as_value();
434
 
}
435
 
  
436
 
} // namespace gnash