1 // Rectangle_as.cpp: ActionScript "Rectangle" class, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
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.
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
21 #include "Rectangle_as.h"
25 #include "as_object.h" // for inheritance
28 #include "Global_as.h"
29 #include "smart_ptr.h" // for boost intrusive_ptr
30 #include "GnashException.h" // for ActionException
33 #include "namedStrings.h"
34 #include "GnashNumeric.h" // isFinite
35 #include "as_function.h"
40 as_value
Rectangle_clone(const fn_call
& fn
);
41 as_value
Rectangle_contains(const fn_call
& fn
);
42 as_value
Rectangle_containsPoint(const fn_call
& fn
);
43 as_value
Rectangle_containsRectangle(const fn_call
& fn
);
44 as_value
Rectangle_equals(const fn_call
& fn
);
45 as_value
Rectangle_inflate(const fn_call
& fn
);
46 as_value
Rectangle_inflatePoint(const fn_call
& fn
);
47 as_value
Rectangle_intersection(const fn_call
& fn
);
48 as_value
Rectangle_intersects(const fn_call
& fn
);
49 as_value
Rectangle_isEmpty(const fn_call
& fn
);
50 as_value
Rectangle_offset(const fn_call
& fn
);
51 as_value
Rectangle_offsetPoint(const fn_call
& fn
);
52 as_value
Rectangle_setEmpty(const fn_call
& fn
);
53 as_value
Rectangle_toString(const fn_call
& fn
);
54 as_value
Rectangle_union(const fn_call
& fn
);
55 as_value
Rectangle_bottom(const fn_call
& fn
);
56 as_value
Rectangle_bottomRight(const fn_call
& fn
);
57 as_value
Rectangle_left(const fn_call
& fn
);
58 as_value
Rectangle_right(const fn_call
& fn
);
59 as_value
Rectangle_size(const fn_call
& fn
);
60 as_value
Rectangle_top(const fn_call
& fn
);
61 as_value
Rectangle_topLeft(const fn_call
& fn
);
62 as_value
Rectangle_ctor(const fn_call
& fn
);
63 as_value
get_flash_geom_rectangle_constructor(const fn_call
& fn
);
68 rectangle_class_init(as_object
& where
, const ObjectURI
& uri
)
70 // TODO: this may not be correct, but it should be enumerable.
72 where
.init_destructive_property(uri
, get_flash_geom_rectangle_constructor
,
80 attachRectangleInterface(as_object
& o
)
82 Global_as
& gl
= getGlobal(o
);
83 o
.init_member("clone", gl
.createFunction(Rectangle_clone
), 0);
84 o
.init_member("contains", gl
.createFunction(Rectangle_contains
), 0);
85 o
.init_member("containsPoint",
86 gl
.createFunction(Rectangle_containsPoint
), 0);
87 o
.init_member("containsRectangle",
88 gl
.createFunction(Rectangle_containsRectangle
), 0);
89 o
.init_member("equals", gl
.createFunction(Rectangle_equals
), 0);
90 o
.init_member("inflate", gl
.createFunction(Rectangle_inflate
), 0);
91 o
.init_member("inflatePoint",
92 gl
.createFunction(Rectangle_inflatePoint
), 0);
93 o
.init_member("intersection",
94 gl
.createFunction(Rectangle_intersection
), 0);
95 o
.init_member("intersects", gl
.createFunction(Rectangle_intersects
), 0);
96 o
.init_member("isEmpty", gl
.createFunction(Rectangle_isEmpty
), 0);
97 o
.init_member("offset", gl
.createFunction(Rectangle_offset
), 0);
98 o
.init_member("offsetPoint", gl
.createFunction(Rectangle_offsetPoint
), 0);
99 o
.init_member("setEmpty", gl
.createFunction(Rectangle_setEmpty
), 0);
100 o
.init_member("toString", gl
.createFunction(Rectangle_toString
), 0);
101 o
.init_member("union", gl
.createFunction(Rectangle_union
), 0);
102 o
.init_property("bottom",
103 Rectangle_bottom
, Rectangle_bottom
, 0);
104 o
.init_property("bottomRight", Rectangle_bottomRight
,
105 Rectangle_bottomRight
, 0);
106 o
.init_property("left", Rectangle_left
,
108 o
.init_property("right", Rectangle_right
,
110 o
.init_property("size", Rectangle_size
,
112 o
.init_property("top", Rectangle_top
,
114 o
.init_property("topLeft", Rectangle_topLeft
,
115 Rectangle_topLeft
, 0);
120 Rectangle_clone(const fn_call
& fn
)
122 // The object will be interpreted as a rectangle. Any Rectangle
123 // properties that the object has (width, height, x, y) are used.
124 as_object
* ptr
= ensure
<ValidThis
>(fn
);
126 as_value x
= getMember(*ptr
, NSV::PROP_X
);
127 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
128 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
129 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
131 as_function
* ctor
= getClassConstructor(fn
, "flash.geom.Rectangle");
132 if (!ctor
) return as_value();
137 return constructInstance(*ctor
, fn
.env(), args
);
141 Rectangle_contains(const fn_call
& fn
)
143 as_object
* ptr
= ensure
<ValidThis
>(fn
);
145 as_value rect_x_as
= getMember(*ptr
, NSV::PROP_X
);
146 as_value rect_width_as
= getMember(*ptr
, NSV::PROP_WIDTH
);
147 as_value rect_y_as
= getMember(*ptr
, NSV::PROP_Y
);
148 as_value rect_height_as
= getMember(*ptr
, NSV::PROP_HEIGHT
);
151 IF_VERBOSE_ASCODING_ERRORS(
152 std::stringstream ss
;
154 log_aserror("flash.geom.Rectangle(%s): %s", ss
.str(),
155 _("missing arguments"));
160 const as_value
& x_as
= fn
.arg(0);
161 const as_value
& y_as
= fn
.arg(1);
165 as_value rect_x1_as
= rect_x_as
;
166 newAdd(rect_x1_as
, rect_width_as
, vm
);
168 as_value rect_y1_as
= rect_y_as
;
169 newAdd(rect_y1_as
, rect_height_as
, vm
);
171 // Points are contained within the Rectangle IFF they lie
172 // on the top or left borders of the rectangle, but not the right or
173 // bottom borders, or they are not on a border but between all.
175 // NOTE: order of tests is important, see actionscript.all/Rectangle.as
177 as_value ret
= newLessThan(x_as
, rect_x_as
, vm
);
178 if (ret
.is_undefined()) return as_value();
179 if (toBool(ret
, vm
)) return as_value(false);
181 ret
= newLessThan(x_as
, rect_x1_as
, vm
);
182 if (ret
.is_undefined()) return as_value();
183 if (!toBool(ret
, vm
)) return as_value(false);
185 ret
= newLessThan(y_as
, rect_y_as
, vm
);
186 if (ret
.is_undefined()) return as_value();
187 if (toBool(ret
, vm
)) return as_value(false);
189 ret
= newLessThan(y_as
, rect_y1_as
, vm
);
190 if (ret
.is_undefined()) return as_value();
191 if (!toBool(ret
, vm
)) return as_value(false);
193 return as_value(true);
198 // This is horrible ActionScript implemented in C++.
200 Rectangle_containsPoint(const fn_call
& fn
)
202 as_object
* ptr
= ensure
<ValidThis
>(fn
);
204 as_object
* arg
= (fn
.nargs
> 0) ? toObject(fn
.arg(0), getVM(fn
)) : 0;
208 as_value thisx
= getMember(*ptr
, NSV::PROP_X
);
209 as_value argx
= arg
? getMember(*arg
, NSV::PROP_X
) : as_value();
212 as_value ret
= newLessThan(argx
, thisx
, vm
);
213 if (ret
.is_undefined()) return as_value();
214 if (toBool(ret
, vm
)) return as_value(false);
216 as_value thisw
= getMember(*ptr
, NSV::PROP_WIDTH
);
218 newAdd(thisx
, thisw
, vm
);
219 ret
= newLessThan(argx
, thisx
, vm
);
220 if (ret
.is_undefined()) return as_value();
221 if (!toBool(ret
, vm
)) return as_value(false);
223 as_value thisy
= getMember(*ptr
, NSV::PROP_Y
);
224 as_value argy
= arg
? getMember(*arg
, NSV::PROP_Y
) : as_value();
227 ret
= newLessThan(argy
, thisy
, vm
);
228 if (ret
.is_undefined()) return as_value();
229 if (toBool(ret
, vm
)) return as_value(false);
231 as_value thish
= getMember(*ptr
, NSV::PROP_HEIGHT
);
233 newAdd(thisy
, thish
, vm
);
234 ret
= newLessThan(argy
, thisy
, vm
);
235 if (ret
.is_undefined()) return as_value();
236 if (!toBool(ret
, vm
)) return as_value(false);
238 return as_value(true);
244 Rectangle_containsRectangle(const fn_call
& fn
)
246 as_object
* ptr
= ensure
<ValidThis
>(fn
);
248 LOG_ONCE( log_unimpl (__FUNCTION__
) );
253 Rectangle_equals(const fn_call
& fn
)
255 as_object
* ptr
= ensure
<ValidThis
>(fn
);
257 if (!fn
.nargs
) return as_value(false);
258 as_object
* comp
= toObject(fn
.arg(0), getVM(fn
));
260 if (!comp
) return as_value(false);
262 if (!comp
->instanceOf(getClassConstructor(fn
, "flash.geom.Rectangle"))) {
263 return as_value(false);
266 if (!equals(getMember(*comp
, NSV::PROP_X
),
267 getMember(*ptr
, NSV::PROP_X
), getVM(fn
))) {
268 return as_value(false);
271 if (!equals(getMember(*comp
, NSV::PROP_Y
),
272 getMember(*ptr
, NSV::PROP_Y
), getVM(fn
))) {
273 return as_value(false);
276 if (!equals(getMember(*comp
, NSV::PROP_WIDTH
),
277 getMember(*ptr
, NSV::PROP_WIDTH
), getVM(fn
))) {
278 return as_value(false);
281 if (!equals(getMember(*comp
, NSV::PROP_HEIGHT
),
282 getMember(*ptr
, NSV::PROP_HEIGHT
), getVM(fn
))) {
283 return as_value(false);
286 return as_value(true);
290 Rectangle_inflate(const fn_call
& fn
)
292 as_object
* ptr
= ensure
<ValidThis
>(fn
);
294 LOG_ONCE( log_unimpl (__FUNCTION__
) );
299 Rectangle_inflatePoint(const fn_call
& fn
)
301 as_object
* ptr
= ensure
<ValidThis
>(fn
);
303 LOG_ONCE( log_unimpl (__FUNCTION__
) );
308 Rectangle_intersection(const fn_call
& fn
)
310 as_object
* ptr
= ensure
<ValidThis
>(fn
);
312 LOG_ONCE( log_unimpl (__FUNCTION__
) );
317 Rectangle_intersects(const fn_call
& fn
)
319 as_object
* ptr
= ensure
<ValidThis
>(fn
);
321 LOG_ONCE( log_unimpl (__FUNCTION__
) );
326 Rectangle_isEmpty(const fn_call
& fn
)
328 as_object
* ptr
= ensure
<ValidThis
>(fn
);
330 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
331 if (w
.is_undefined() || w
.is_null()) return as_value(true);
333 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
334 if (h
.is_undefined() || h
.is_null()) return as_value(true);
336 double wn
= toNumber(w
, getVM(fn
));
337 if (!isFinite(wn
) || wn
<= 0) return as_value(true);
339 double hn
= toNumber(h
, getVM(fn
));
340 if (!isFinite(hn
) || hn
<= 0) return as_value(true);
342 return as_value(false);
346 Rectangle_offset(const fn_call
& fn
)
348 as_object
* ptr
= ensure
<ValidThis
>(fn
);
350 as_value xdelta
= fn
.nargs
> 0 ? fn
.arg(0) : as_value();
351 as_value ydelta
= fn
.nargs
> 1 ? fn
.arg(1) : as_value();
353 as_value x
= getMember(*ptr
, NSV::PROP_X
);
354 newAdd(x
, xdelta
, getVM(fn
));
355 ptr
->set_member(NSV::PROP_X
, x
);
357 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
358 newAdd(y
, ydelta
, getVM(fn
));
359 ptr
->set_member(NSV::PROP_Y
, y
);
365 Rectangle_offsetPoint(const fn_call
& fn
)
367 as_object
* ptr
= ensure
<ValidThis
>(fn
);
369 as_object
* arg
= (fn
.nargs
> 0) ? toObject(fn
.arg(0), getVM(fn
)) : 0;
370 if (!arg
) return as_value();
372 as_value xdelta
= getMember(*arg
, NSV::PROP_X
);
373 as_value ydelta
= getMember(*arg
, NSV::PROP_Y
);
375 as_value x
= getMember(*ptr
, NSV::PROP_X
);
376 newAdd(x
, xdelta
, getVM(fn
));
377 ptr
->set_member(NSV::PROP_X
, x
);
379 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
380 newAdd(y
, ydelta
, getVM(fn
));
381 ptr
->set_member(NSV::PROP_Y
, y
);
387 Rectangle_setEmpty(const fn_call
& fn
)
389 as_object
* ptr
= ensure
<ValidThis
>(fn
);
390 ptr
->set_member(NSV::PROP_X
, 0.0);
391 ptr
->set_member(NSV::PROP_Y
, 0.0);
392 ptr
->set_member(NSV::PROP_WIDTH
, 0.0);
393 ptr
->set_member(NSV::PROP_HEIGHT
, 0.0);
398 Rectangle_toString(const fn_call
& fn
)
400 as_object
* ptr
= ensure
<ValidThis
>(fn
);
402 as_value x
= getMember(*ptr
, NSV::PROP_X
);
403 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
404 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
405 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
411 newAdd(ret
, ", y=", vm
);
413 newAdd(ret
, ", w=", vm
);
415 newAdd(ret
, ", h=", vm
);
417 newAdd(ret
, ")", vm
);
423 Rectangle_union(const fn_call
& fn
)
425 as_object
* ptr
= ensure
<ValidThis
>(fn
);
427 LOG_ONCE( log_unimpl (__FUNCTION__
) );
432 Rectangle_bottom(const fn_call
& fn
)
434 as_object
* ptr
= ensure
<ValidThis
>(fn
);
437 as_value b
= getMember(*ptr
, NSV::PROP_Y
);
438 as_value height
= getMember(*ptr
, NSV::PROP_HEIGHT
);
439 newAdd(b
, height
, getVM(fn
));
442 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
443 as_value height
= fn
.arg(0);
444 subtract(height
, y
, getVM(fn
));
445 ptr
->set_member(NSV::PROP_HEIGHT
, height
);
451 Rectangle_bottomRight(const fn_call
& fn
)
453 as_object
* ptr
= ensure
<ValidThis
>(fn
);
457 as_value x
= getMember(*ptr
, NSV::PROP_X
);
458 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
459 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
460 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
466 as_value
point(findObject(fn
.env(), "flash.geom.Point"));
468 as_function
* pointCtor
= point
.to_function();
471 IF_VERBOSE_ASCODING_ERRORS(
472 log_aserror("Failed to construct flash.geom.Point!");
480 return constructInstance(*pointCtor
, fn
.env(), args
);
483 IF_VERBOSE_ASCODING_ERRORS(
484 log_aserror(_("Attempt to set read-only property %s"),
485 "Rectangle.bottomRight");
492 Rectangle_left(const fn_call
& fn
)
494 as_object
* ptr
= ensure
<ValidThis
>(fn
);
497 return getMember(*ptr
, NSV::PROP_X
);
499 as_value oldx
= getMember(*ptr
, NSV::PROP_X
);
501 as_value newx
= fn
.arg(0);
502 ptr
->set_member(NSV::PROP_X
, newx
);
504 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
507 subtract(oldx
, newx
, vm
);
509 ptr
->set_member(NSV::PROP_WIDTH
, w
);
515 Rectangle_right(const fn_call
& fn
)
517 as_object
* ptr
= ensure
<ValidThis
>(fn
);
520 as_value r
= getMember(*ptr
, NSV::PROP_X
);
521 as_value width
= getMember(*ptr
, NSV::PROP_WIDTH
);
522 newAdd(r
, width
, getVM(fn
));
526 as_value x
= getMember(*ptr
, NSV::PROP_X
);
528 as_value width
= fn
.arg(0);
529 subtract(width
, x
, getVM(fn
));
530 ptr
->set_member(NSV::PROP_WIDTH
, width
);
535 Rectangle_size(const fn_call
& fn
)
537 as_object
* ptr
= ensure
<ValidThis
>(fn
);
540 as_value w
= getMember(*ptr
, NSV::PROP_WIDTH
);
541 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
543 as_function
* pointCtor
= getClassConstructor(fn
, "flash.geom.Point");
545 IF_VERBOSE_ASCODING_ERRORS(
546 log_aserror("Failed to construct flash.geom.Point!");
554 return constructInstance(*pointCtor
, fn
.env(), args
);
557 IF_VERBOSE_ASCODING_ERRORS(
558 log_aserror(_("Attempt to set read-only property %s"),
566 Rectangle_top(const fn_call
& fn
)
568 as_object
* ptr
= ensure
<ValidThis
>(fn
);
572 return getMember(*ptr
, NSV::PROP_Y
);
576 as_value oldy
= getMember(*ptr
, NSV::PROP_Y
);
578 as_value newy
= fn
.arg(0);
579 ptr
->set_member(NSV::PROP_Y
, newy
);
581 as_value h
= getMember(*ptr
, NSV::PROP_HEIGHT
);
584 subtract(oldy
, newy
, vm
);
586 ptr
->set_member(NSV::PROP_HEIGHT
, h
);
592 Rectangle_topLeft(const fn_call
& fn
)
594 as_object
* ptr
= ensure
<ValidThis
>(fn
);
598 as_value x
= getMember(*ptr
, NSV::PROP_X
);
599 as_value y
= getMember(*ptr
, NSV::PROP_Y
);
601 as_function
* pointCtor
= getClassConstructor(fn
, "flash.geom.Point");
603 IF_VERBOSE_ASCODING_ERRORS(
604 log_aserror("Failed to construct flash.geom.Point!");
612 return constructInstance(*pointCtor
, fn
.env(), args
);
616 IF_VERBOSE_ASCODING_ERRORS(
617 log_aserror(_("Attempt to set read-only property %s"),
618 "Rectangle.topLeft");
626 Rectangle_ctor(const fn_call
& fn
)
629 as_object
* obj
= ensure
<ValidThis
>(fn
);
633 const ObjectURI
& setEmpty
= getURI(getVM(fn
), "setEmpty");
634 callMethod(obj
, setEmpty
);
639 obj
->set_member(NSV::PROP_X
, fn
.arg(0));
640 obj
->set_member(NSV::PROP_Y
, fn
.nargs
> 1 ? fn
.arg(1) : as_value());
641 obj
->set_member(NSV::PROP_WIDTH
, fn
.nargs
> 2 ? fn
.arg(2) : as_value());
642 obj
->set_member(NSV::PROP_HEIGHT
, fn
.nargs
> 3 ? fn
.arg(3) : as_value());
648 get_flash_geom_rectangle_constructor(const fn_call
& fn
)
650 log_debug("Loading flash.geom.Rectangle class");
651 Global_as
& gl
= getGlobal(fn
);
652 as_object
* proto
= createObject(gl
);
653 attachRectangleInterface(*proto
);
654 return gl
.createClass(&Rectangle_ctor
, proto
);
657 } // anonymous namespace
658 } // end of gnash namespace