1
// Point_as.cpp: ActionScript "Point" class, for Gnash.
3
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
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.
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.
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
21
#include "as_object.h" // for inheritance
24
#include "smart_ptr.h" // for boost intrusive_ptr
25
#include "builtin_function.h" // need builtin_function
26
#include "GnashException.h" // for ActionException
27
#include "Object.h" // for AS inheritance
28
#include "VM.h" // for addStatics
29
#include "utility.h" // isFinite
35
static as_value Point_add(const fn_call& fn);
36
static as_value Point_clone(const fn_call& fn);
37
static as_value Point_equals(const fn_call& fn);
38
static as_value Point_normalize(const fn_call& fn);
39
static as_value Point_offset(const fn_call& fn);
40
static as_value Point_subtract(const fn_call& fn);
41
static as_value Point_toString(const fn_call& fn);
42
static as_value Point_length_getset(const fn_call& fn);
44
static as_value Point_distance(const fn_call& fn);
45
static as_value Point_interpolate(const fn_call& fn);
46
static as_value Point_polar(const fn_call& fn);
48
as_value Point_ctor(const fn_call& fn);
51
attachPointInterface(as_object& o)
55
o.init_member("add", new builtin_function(Point_add), fl);
56
o.init_member("clone", new builtin_function(Point_clone), fl);
57
o.init_member("equals", new builtin_function(Point_equals), fl);
58
o.init_member("normalize", new builtin_function(Point_normalize), fl);
59
o.init_member("offset", new builtin_function(Point_offset), fl);
60
o.init_member("subtract", new builtin_function(Point_subtract), fl);
61
o.init_member("toString", new builtin_function(Point_toString), fl);
62
o.init_property("length", Point_length_getset, Point_length_getset, fl);
66
attachPointStaticProperties(as_object& o)
68
o.init_member("distance", new builtin_function(Point_distance), 0);
69
o.init_member("interpolate", new builtin_function(Point_interpolate), 0);
70
o.init_member("polar", new builtin_function(Point_polar), 0);
76
static boost::intrusive_ptr<as_object> o;
80
// TODO: check if this class should inherit from Object
81
// or from a different class
82
o = new as_object(getObjectInterface());
83
VM::get().addStatic(o.get());
85
attachPointInterface(*o);
93
class Point_as: public as_object
98
as_object(getPointInterface())
105
Point_add(const fn_call& fn)
107
boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
110
ptr->get_member(NSV::PROP_X, &x);
111
ptr->get_member(NSV::PROP_Y, &y);
117
IF_VERBOSE_ASCODING_ERRORS(
118
log_aserror(_("%s: missing arguments"), "Point.add()");
123
IF_VERBOSE_ASCODING_ERRORS(
126
std::stringstream ss; fn.dump_args(ss);
127
log_aserror("Point.add(%s): %s", ss.str(), _("arguments after first discarded"));
130
const as_value& arg1 = fn.arg(0);
131
as_object* o = arg1.to_object().get();
134
IF_VERBOSE_ASCODING_ERRORS(
135
std::stringstream ss; fn.dump_args(ss);
136
log_aserror("Point.add(%s): %s", ss.str(), _("first argument doesn't cast to object"));
141
if ( ! o->get_member(NSV::PROP_X, &x1) )
143
IF_VERBOSE_ASCODING_ERRORS(
144
std::stringstream ss; fn.dump_args(ss);
145
log_aserror("Point.add(%s): %s", ss.str(),
146
_("first argument cast to object doesn't contain an 'x' member"));
149
if ( ! o->get_member(NSV::PROP_Y, &y1) )
151
IF_VERBOSE_ASCODING_ERRORS(
152
std::stringstream ss; fn.dump_args(ss);
153
log_aserror("Point.add(%s): %s", ss.str(),
154
_("first argument cast to object doesn't contain an 'y' member"));
163
boost::intrusive_ptr<as_object> ret = new Point_as;
164
ret->set_member(NSV::PROP_X, x);
165
ret->set_member(NSV::PROP_Y, y);
167
return as_value(ret.get());
171
Point_clone(const fn_call& fn)
173
boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
176
ptr->get_member(NSV::PROP_X, &x);
177
ptr->get_member(NSV::PROP_Y, &y);
179
boost::intrusive_ptr<as_object> ret = new Point_as;
180
ret->set_member(NSV::PROP_X, x);
181
ret->set_member(NSV::PROP_Y, y);
183
return as_value(ret.get());
187
Point_equals(const fn_call& fn)
189
boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
193
IF_VERBOSE_ASCODING_ERRORS(
194
log_aserror(_("%s: missing arguments"), "Point.equals()");
196
return as_value(false);
199
const as_value& arg1 = fn.arg(0);
200
if ( ! arg1.is_object() )
202
IF_VERBOSE_ASCODING_ERRORS(
203
std::stringstream ss; fn.dump_args(ss);
204
log_aserror("Point.equals(%s): %s", ss.str(), _("First arg must be an object"));
206
return as_value(false);
208
as_object* o = arg1.to_object().get();
210
if ( ! o->instanceOf(getFlashGeomPointConstructor()) )
212
IF_VERBOSE_ASCODING_ERRORS(
213
std::stringstream ss; fn.dump_args(ss);
214
log_aserror("Point.equals(%s): %s %s", ss.str(), _("First arg must be an instance of"), "flash.geom.Point");
216
return as_value(false);
220
ptr->get_member(NSV::PROP_X, &x);
221
ptr->get_member(NSV::PROP_Y, &y);
224
o->get_member(NSV::PROP_X, &x1);
225
o->get_member(NSV::PROP_Y, &y1);
227
return as_value(x.equals(x1) && y.equals(y1));
231
Point_normalize(const fn_call& fn)
233
boost::intrusive_ptr<Point_as> ptr = ensureType<Point_as>(fn.this_ptr);
239
IF_VERBOSE_ASCODING_ERRORS(
240
log_aserror(_("%s: missing arguments"), "Point.normalize()");
246
IF_VERBOSE_ASCODING_ERRORS(
249
std::stringstream ss; fn.dump_args(ss);
250
log_aserror("Point.normalize(%s): %s", ss.str(), _("arguments after first discarded"));
257
// newlen may be NaN, and we'd still be updating x/y
258
// see actionscript.all/Point.as
259
double newlen = argval.to_number();
262
ptr->get_member(NSV::PROP_X, &xval);
263
ptr->get_member(NSV::PROP_Y, &yval);
265
double x = xval.to_number();
266
if ( ! utility::isFinite(x) ) return as_value();
267
double y = yval.to_number();
268
if ( ! utility::isFinite(y) ) return as_value();
270
if ( x == 0 && y == 0 ) return as_value();
272
double curlen = std::sqrt(x*x+y*y);
273
double fact = newlen/curlen;
276
xval.set_double( xval.to_number() * fact );
277
yval.set_double( yval.to_number() * fact );
278
ptr->set_member(NSV::PROP_X, xval);
279
ptr->set_member(NSV::PROP_Y, yval);
285
Point_offset(const fn_call& fn)
287
boost::intrusive_ptr<Point_as> ptr = ensureType<Point_as>(fn.this_ptr);
290
ptr->get_member(NSV::PROP_X, &x);
291
ptr->get_member(NSV::PROP_Y, &y);
297
if ( fn.nargs > 1 ) yoff = fn.arg(1);
303
ptr->set_member(NSV::PROP_X, x);
304
ptr->set_member(NSV::PROP_Y, y);
310
Point_subtract(const fn_call& fn)
312
boost::intrusive_ptr<Point_as> ptr = ensureType<Point_as>(fn.this_ptr);
315
ptr->get_member(NSV::PROP_X, &x);
316
ptr->get_member(NSV::PROP_Y, &y);
322
IF_VERBOSE_ASCODING_ERRORS(
323
log_aserror(_("%s: missing arguments"), "Point.add()");
328
IF_VERBOSE_ASCODING_ERRORS(
331
std::stringstream ss; fn.dump_args(ss);
332
log_aserror("Point.add(%s): %s", ss.str(), _("arguments after first discarded"));
335
const as_value& arg1 = fn.arg(0);
336
as_object* o = arg1.to_object().get();
339
IF_VERBOSE_ASCODING_ERRORS(
340
std::stringstream ss; fn.dump_args(ss);
341
log_aserror("Point.add(%s): %s", ss.str(), _("first argument doesn't cast to object"));
346
if ( ! o->get_member(NSV::PROP_X, &x1) )
348
IF_VERBOSE_ASCODING_ERRORS(
349
std::stringstream ss; fn.dump_args(ss);
350
log_aserror("Point.add(%s): %s", ss.str(),
351
_("first argument casted to object doesn't contain an 'x' member"));
354
if ( ! o->get_member(NSV::PROP_Y, &y1) )
356
IF_VERBOSE_ASCODING_ERRORS(
357
std::stringstream ss; fn.dump_args(ss);
358
log_aserror("Point.add(%s): %s", ss.str(),
359
_("first argument casted to object doesn't contain an 'y' member"));
365
x.set_double(x.to_number() - x1.to_number());
366
y.set_double(y.to_number() - y1.to_number());
368
boost::intrusive_ptr<as_object> ret = new Point_as;
369
ret->set_member(NSV::PROP_X, x);
370
ret->set_member(NSV::PROP_Y, y);
372
return as_value(ret.get());
376
Point_toString(const fn_call& fn)
378
boost::intrusive_ptr<Point_as> ptr = ensureType<Point_as>(fn.this_ptr);
381
ptr->get_member(NSV::PROP_X, &x);
382
ptr->get_member(NSV::PROP_Y, &y);
384
std::stringstream ss;
385
ss << "(x=" << x.to_string()
386
<< ", y=" << y.to_string()
389
return as_value(ss.str());
393
Point_length_getset(const fn_call& fn)
395
boost::intrusive_ptr<Point_as> ptr = ensureType<Point_as>(fn.this_ptr);
397
if ( ! fn.nargs ) // getter
400
ptr->get_member(NSV::PROP_X, &xval);
401
ptr->get_member(NSV::PROP_Y, &yval);
402
double x = xval.to_number();
403
double y = yval.to_number();
405
double l = std::sqrt(x*x+y*y);
410
IF_VERBOSE_ASCODING_ERRORS(
411
log_aserror(_("Attempt to set read-only property %s"), "Point.length");
418
Point_distance(const fn_call& fn)
422
IF_VERBOSE_ASCODING_ERRORS(
423
std::stringstream ss; fn.dump_args(ss);
424
log_aserror("Point.distance(%s): %s", ss.str(), _("missing arguments"));
429
IF_VERBOSE_ASCODING_ERRORS(
432
std::stringstream ss; fn.dump_args(ss);
433
log_aserror("Point.distance(%s): %s", ss.str(), _("arguments after first two discarded"));
437
const as_value& arg1 = fn.arg(0);
438
if ( ! arg1.is_object() )
440
IF_VERBOSE_ASCODING_ERRORS(
441
std::stringstream ss; fn.dump_args(ss);
442
log_aserror("Point.distance(%s): %s", ss.str(), _("First arg must be an object"));
446
as_object* o1 = arg1.to_object().get();
448
if ( ! o1->instanceOf(getFlashGeomPointConstructor()) )
450
IF_VERBOSE_ASCODING_ERRORS(
451
std::stringstream ss; fn.dump_args(ss);
452
log_aserror("Point.equals(%s): %s %s", ss.str(), _("First arg must be an instance of"), "flash.geom.Point");
457
const as_value& arg2 = fn.arg(1);
458
as_object* o2 = arg2.to_object().get();
460
// it seems there's no need to check arg2 (see actionscript.all/Point.as)
463
o1->get_member(NSV::PROP_X, &x1val);
464
double x1 = x1val.to_number();
465
//if ( ! utility::isFinite(x1) ) return as_value(NaN);
468
o1->get_member(NSV::PROP_Y, &y1val);
469
double y1 = y1val.to_number();
470
//if ( ! utility::isFinite(y1) ) return as_value(NaN);
473
o2->get_member(NSV::PROP_X, &x2val);
474
double x2 = x2val.to_number();
475
//if ( ! utility::isFinite(x2) ) return as_value(NaN);
478
o2->get_member(NSV::PROP_Y, &y2val);
479
double y2 = y2val.to_number();
480
//if ( ! utility::isFinite(y2) ) return as_value(NaN);
482
double hside = x2 - x1; // p1.x - p0.x;
483
double vside = y2 - y1; // p1.y - p0.y;
485
double sqdist = hside*hside + vside*vside;
486
double dist = std::sqrt(sqdist);
488
return as_value(dist);
492
Point_interpolate(const fn_call& fn)
502
IF_VERBOSE_ASCODING_ERRORS(
503
std::stringstream ss; fn.dump_args(ss);
504
log_aserror("Point.interpolate(%s): %s", ss.str(), _("missing arguments"));
509
IF_VERBOSE_ASCODING_ERRORS(
512
std::stringstream ss; fn.dump_args(ss);
513
log_aserror("Point.interpolate(%s): %s", ss.str(), _("arguments after first three discarded"));
517
const as_value& p0val = fn.arg(0);
518
as_object* p0 = p0val.to_object().get();
521
IF_VERBOSE_ASCODING_ERRORS(
522
std::stringstream ss; fn.dump_args(ss);
523
log_aserror("Point.interpolate(%s): %s", ss.str(), _("first argument doesn't cast to object"));
528
p0->get_member(NSV::PROP_X, &x0val);
529
p0->get_member(NSV::PROP_Y, &y0val);
532
const as_value& p1val = fn.arg(1);
533
as_object* p1 = p1val.to_object().get();
536
IF_VERBOSE_ASCODING_ERRORS(
537
std::stringstream ss; fn.dump_args(ss);
538
log_aserror("Point.interpolate(%s): %s", ss.str(), _("second argument doesn't cast to object"));
543
p1->get_member(NSV::PROP_X, &x1val);
544
p1->get_member(NSV::PROP_Y, &y1val);
551
double x0 = x0val.to_number();
552
double y0 = y0val.to_number();
553
double x1 = x1val.to_number();
554
double y1 = y1val.to_number();
555
double mu = muval.to_number();
557
// newX = b.x + ( muval * (a.x - b.x) );
558
// newY = b.y + ( muval * (a.y - b.y) );
560
as_value xoff = mu * (x0 - x1);
561
as_value yoff = mu * (y0 - y1);
563
//log_debug("xoff:%s, yoff:%s, x1val:%s, y1val:%s", xoff, yoff, x1val, y1val);
565
as_value x = x1val; // copy to avoid changing stack value
567
as_value y = y1val; // copy to avoid changing stack value
570
boost::intrusive_ptr<as_object> ret = new Point_as;
571
ret->set_member(NSV::PROP_X, as_value(x));
572
ret->set_member(NSV::PROP_Y, as_value(y));
574
return as_value(ret.get());
578
Point_polar(const fn_call& fn)
580
as_value lval; // length
581
as_value aval; // angle (radians)
586
if ( fn.nargs > 1 ) aval=fn.arg(1);
589
IF_VERBOSE_ASCODING_ERRORS(
590
std::stringstream ss; fn.dump_args(ss);
591
log_aserror("Point.polar(%s): %s", ss.str(), _("missing arguments"));
597
IF_VERBOSE_ASCODING_ERRORS(
598
std::stringstream ss; fn.dump_args(ss);
599
log_aserror("Point.polar(%s): %s", ss.str(), _("missing arguments"));
603
double len = lval.to_number();
604
double angle = aval.to_number();
606
double x = len * std::cos(angle);
607
double y = len * std::sin(angle);
611
boost::intrusive_ptr<as_object> obj = new Point_as;
613
obj->set_member(NSV::PROP_X, x);
614
obj->set_member(NSV::PROP_Y, y);
616
return as_value(obj.get());
621
Point_ctor(const fn_call& fn)
623
boost::intrusive_ptr<as_object> obj = new Point_as;
637
if ( fn.nargs < 2 ) break;
639
if ( fn.nargs < 3 ) break;
640
IF_VERBOSE_ASCODING_ERRORS(
641
std::stringstream ss;
643
log_aserror("flash.geom.Point(%s): %s", ss.str(), _("arguments after the first two discarded"));
648
obj->set_member(NSV::PROP_X, x);
649
obj->set_member(NSV::PROP_Y, y);
651
return as_value(obj.get()); // will keep alive
655
as_function* getFlashGeomPointConstructor()
657
static builtin_function* cl=NULL;
660
cl=new builtin_function(&Point_ctor, getPointInterface());
661
VM::get().addStatic(cl);
662
attachPointStaticProperties(*cl);
667
static as_value get_flash_geom_point_constructor(const fn_call& /*fn*/)
669
log_debug("Loading flash.geom.Point class");
671
return getFlashGeomPointConstructor();
674
boost::intrusive_ptr<as_object> init_Point_instance()
676
return boost::intrusive_ptr<as_object>(new Point_as);
680
void Point_class_init(as_object& where)
682
// Register _global.Point
683
string_table& st = where.getVM().getStringTable();
684
where.init_destructive_property(st.find("Point"), get_flash_geom_point_constructor);
687
} // end of gnash namespace