1 // Rectangle_as.cpp: ActionScript "Rectangle" class, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software 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.
15 //
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 //
20
21 #include "Rectangle_as.h"
22
23 #include <sstream>
24
25 #include "as_object.h" // for inheritance
26 #include "log.h"
27 #include "fn_call.h"
28 #include "Global_as.h"
29 #include "GnashException.h" // for ActionException
30 #include "VM.h"
31 #include "as_value.h"
32 #include "namedStrings.h"
33 #include "GnashNumeric.h" // isFinite
34 #include "as_function.h"
35
36 namespace gnash {
37
38 namespace {
39 as_value Rectangle_clone(const fn_call& fn);
40 as_value Rectangle_contains(const fn_call& fn);
41 as_value Rectangle_containsPoint(const fn_call& fn);
42 as_value Rectangle_containsRectangle(const fn_call& fn);
43 as_value Rectangle_equals(const fn_call& fn);
44 as_value Rectangle_inflate(const fn_call& fn);
45 as_value Rectangle_inflatePoint(const fn_call& fn);
46 as_value Rectangle_intersection(const fn_call& fn);
47 as_value Rectangle_intersects(const fn_call& fn);
48 as_value Rectangle_isEmpty(const fn_call& fn);
49 as_value Rectangle_offset(const fn_call& fn);
50 as_value Rectangle_offsetPoint(const fn_call& fn);
51 as_value Rectangle_setEmpty(const fn_call& fn);
52 as_value Rectangle_toString(const fn_call& fn);
53 as_value Rectangle_union(const fn_call& fn);
54 as_value Rectangle_bottom(const fn_call& fn);
55 as_value Rectangle_bottomRight(const fn_call& fn);
56 as_value Rectangle_left(const fn_call& fn);
57 as_value Rectangle_right(const fn_call& fn);
58 as_value Rectangle_size(const fn_call& fn);
59 as_value Rectangle_top(const fn_call& fn);
60 as_value Rectangle_topLeft(const fn_call& fn);
61 as_value Rectangle_ctor(const fn_call& fn);
62 as_value get_flash_geom_rectangle_constructor(const fn_call& fn);
63
64 }
65
66 void
rectangle_class_init(as_object & where,const ObjectURI & uri)67 rectangle_class_init(as_object& where, const ObjectURI& uri)
68 {
69 // TODO: this may not be correct, but it should be enumerable.
70 const int flags = 0;
71 where.init_destructive_property(uri, get_flash_geom_rectangle_constructor,
72 flags);
73 }
74
75
76 namespace {
77
78 void
attachRectangleInterface(as_object & o)79 attachRectangleInterface(as_object& o)
80 {
81 Global_as& gl = getGlobal(o);
82 o.init_member("clone", gl.createFunction(Rectangle_clone), 0);
83 o.init_member("contains", gl.createFunction(Rectangle_contains), 0);
84 o.init_member("containsPoint",
85 gl.createFunction(Rectangle_containsPoint), 0);
86 o.init_member("containsRectangle",
87 gl.createFunction(Rectangle_containsRectangle), 0);
88 o.init_member("equals", gl.createFunction(Rectangle_equals), 0);
89 o.init_member("inflate", gl.createFunction(Rectangle_inflate), 0);
90 o.init_member("inflatePoint",
91 gl.createFunction(Rectangle_inflatePoint), 0);
92 o.init_member("intersection",
93 gl.createFunction(Rectangle_intersection), 0);
94 o.init_member("intersects", gl.createFunction(Rectangle_intersects), 0);
95 o.init_member("isEmpty", gl.createFunction(Rectangle_isEmpty), 0);
96 o.init_member("offset", gl.createFunction(Rectangle_offset), 0);
97 o.init_member("offsetPoint", gl.createFunction(Rectangle_offsetPoint), 0);
98 o.init_member("setEmpty", gl.createFunction(Rectangle_setEmpty), 0);
99 o.init_member("toString", gl.createFunction(Rectangle_toString), 0);
100 o.init_member("union", gl.createFunction(Rectangle_union), 0);
101 o.init_property("bottom",
102 Rectangle_bottom, Rectangle_bottom, 0);
103 o.init_property("bottomRight", Rectangle_bottomRight,
104 Rectangle_bottomRight, 0);
105 o.init_property("left", Rectangle_left,
106 Rectangle_left, 0);
107 o.init_property("right", Rectangle_right,
108 Rectangle_right, 0);
109 o.init_property("size", Rectangle_size,
110 Rectangle_size, 0);
111 o.init_property("top", Rectangle_top,
112 Rectangle_top, 0);
113 o.init_property("topLeft", Rectangle_topLeft,
114 Rectangle_topLeft, 0);
115 }
116
117
118 as_value
Rectangle_clone(const fn_call & fn)119 Rectangle_clone(const fn_call& fn)
120 {
121 // The object will be interpreted as a rectangle. Any Rectangle
122 // properties that the object has (width, height, x, y) are used.
123 as_object* ptr = ensure<ValidThis>(fn);
124
125 as_value x = getMember(*ptr, NSV::PROP_X);
126 as_value y = getMember(*ptr, NSV::PROP_Y);
127 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
128 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
129
130 as_function* ctor = getClassConstructor(fn, "flash.geom.Rectangle");
131 if (!ctor) return as_value();
132
133 fn_call::Args args;
134 args += x, y, w, h;
135
136 return constructInstance(*ctor, fn.env(), args);
137 }
138
139 as_value
Rectangle_contains(const fn_call & fn)140 Rectangle_contains(const fn_call& fn)
141 {
142 as_object* ptr = ensure<ValidThis>(fn);
143
144 as_value rect_x_as = getMember(*ptr, NSV::PROP_X);
145 as_value rect_width_as = getMember(*ptr, NSV::PROP_WIDTH);
146 as_value rect_y_as = getMember(*ptr, NSV::PROP_Y);
147 as_value rect_height_as = getMember(*ptr, NSV::PROP_HEIGHT);
148
149 if (fn.nargs < 2) {
150 IF_VERBOSE_ASCODING_ERRORS(
151 std::stringstream ss;
152 fn.dump_args(ss);
153 log_aserror(_("flash.geom.Rectangle(%s): %s"), ss.str(),
154 _("missing arguments"));
155 );
156 return as_value();
157 }
158
159 const as_value& x_as = fn.arg(0);
160 const as_value& y_as = fn.arg(1);
161
162 VM& vm = getVM(fn);
163
164 as_value rect_x1_as = rect_x_as;
165 newAdd(rect_x1_as, rect_width_as, vm);
166
167 as_value rect_y1_as = rect_y_as;
168 newAdd(rect_y1_as, rect_height_as, vm);
169
170 // Points are contained within the Rectangle IFF they lie
171 // on the top or left borders of the rectangle, but not the right or
172 // bottom borders, or they are not on a border but between all.
173
174 // NOTE: order of tests is important, see actionscript.all/Rectangle.as
175
176 as_value ret = newLessThan(x_as, rect_x_as, vm);
177 if (ret.is_undefined()) return as_value();
178 if (toBool(ret, vm)) return as_value(false);
179
180 ret = newLessThan(x_as, rect_x1_as, vm);
181 if (ret.is_undefined()) return as_value();
182 if (!toBool(ret, vm)) return as_value(false);
183
184 ret = newLessThan(y_as, rect_y_as, vm);
185 if (ret.is_undefined()) return as_value();
186 if (toBool(ret, vm)) return as_value(false);
187
188 ret = newLessThan(y_as, rect_y1_as, vm);
189 if (ret.is_undefined()) return as_value();
190 if (!toBool(ret, vm)) return as_value(false);
191
192 return as_value(true);
193
194 }
195
196
197 // This is horrible ActionScript implemented in C++.
198 as_value
Rectangle_containsPoint(const fn_call & fn)199 Rectangle_containsPoint(const fn_call& fn)
200 {
201 as_object* ptr = ensure<ValidThis>(fn);
202
203 as_object* arg = (fn.nargs > 0) ? toObject(fn.arg(0), getVM(fn)) : nullptr;
204
205 VM& vm = getVM(fn);
206
207 as_value thisx = getMember(*ptr, NSV::PROP_X);
208 as_value argx = arg ? getMember(*arg, NSV::PROP_X) : as_value();
209
210 // argx >= thisx
211 as_value ret = newLessThan(argx, thisx, vm);
212 if (ret.is_undefined()) return as_value();
213 if (toBool(ret, vm)) return as_value(false);
214
215 as_value thisw = getMember(*ptr, NSV::PROP_WIDTH);
216
217 newAdd(thisx, thisw, vm);
218 ret = newLessThan(argx, thisx, vm);
219 if (ret.is_undefined()) return as_value();
220 if (!toBool(ret, vm)) return as_value(false);
221
222 as_value thisy = getMember(*ptr, NSV::PROP_Y);
223 as_value argy = arg ? getMember(*arg, NSV::PROP_Y) : as_value();
224
225 // argy >= thisy
226 ret = newLessThan(argy, thisy, vm);
227 if (ret.is_undefined()) return as_value();
228 if (toBool(ret, vm)) return as_value(false);
229
230 as_value thish = getMember(*ptr, NSV::PROP_HEIGHT);
231
232 newAdd(thisy, thish, vm);
233 ret = newLessThan(argy, thisy, vm);
234 if (ret.is_undefined()) return as_value();
235 if (!toBool(ret, vm)) return as_value(false);
236
237 return as_value(true);
238
239
240 }
241
242 as_value
Rectangle_containsRectangle(const fn_call & fn)243 Rectangle_containsRectangle(const fn_call& fn)
244 {
245 as_object* ptr = ensure<ValidThis>(fn);
246 UNUSED(ptr);
247 LOG_ONCE(log_unimpl(__FUNCTION__) );
248 return as_value();
249 }
250
251 as_value
Rectangle_equals(const fn_call & fn)252 Rectangle_equals(const fn_call& fn)
253 {
254 as_object* ptr = ensure<ValidThis>(fn);
255
256 if (!fn.nargs) return as_value(false);
257 as_object* comp = toObject(fn.arg(0), getVM(fn));
258
259 if (!comp) return as_value(false);
260
261 if (!comp->instanceOf(getClassConstructor(fn, "flash.geom.Rectangle"))) {
262 return as_value(false);
263 }
264
265 if (!equals(getMember(*comp, NSV::PROP_X),
266 getMember(*ptr, NSV::PROP_X), getVM(fn))) {
267 return as_value(false);
268 }
269
270 if (!equals(getMember(*comp, NSV::PROP_Y),
271 getMember(*ptr, NSV::PROP_Y), getVM(fn))) {
272 return as_value(false);
273 }
274
275 if (!equals(getMember(*comp, NSV::PROP_WIDTH),
276 getMember(*ptr, NSV::PROP_WIDTH), getVM(fn))) {
277 return as_value(false);
278 }
279
280 if (!equals(getMember(*comp, NSV::PROP_HEIGHT),
281 getMember(*ptr, NSV::PROP_HEIGHT), getVM(fn))) {
282 return as_value(false);
283 }
284
285 return as_value(true);
286 }
287
288 as_value
Rectangle_inflate(const fn_call & fn)289 Rectangle_inflate(const fn_call& fn)
290 {
291 as_object* ptr = ensure<ValidThis>(fn);
292 UNUSED(ptr);
293 LOG_ONCE(log_unimpl(__FUNCTION__) );
294 return as_value();
295 }
296
297 as_value
Rectangle_inflatePoint(const fn_call & fn)298 Rectangle_inflatePoint(const fn_call& fn)
299 {
300 as_object* ptr = ensure<ValidThis>(fn);
301 UNUSED(ptr);
302 LOG_ONCE(log_unimpl(__FUNCTION__) );
303 return as_value();
304 }
305
306 as_value
Rectangle_intersection(const fn_call & fn)307 Rectangle_intersection(const fn_call& fn)
308 {
309 as_object* ptr = ensure<ValidThis>(fn);
310 UNUSED(ptr);
311 LOG_ONCE(log_unimpl(__FUNCTION__) );
312 return as_value();
313 }
314
315 as_value
Rectangle_intersects(const fn_call & fn)316 Rectangle_intersects(const fn_call& fn)
317 {
318 as_object* ptr = ensure<ValidThis>(fn);
319 UNUSED(ptr);
320 LOG_ONCE(log_unimpl(__FUNCTION__) );
321 return as_value();
322 }
323
324 as_value
Rectangle_isEmpty(const fn_call & fn)325 Rectangle_isEmpty(const fn_call& fn)
326 {
327 as_object* ptr = ensure<ValidThis>(fn);
328
329 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
330 if (w.is_undefined() || w.is_null()) return as_value(true);
331
332 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
333 if (h.is_undefined() || h.is_null()) return as_value(true);
334
335 double wn = toNumber(w, getVM(fn));
336 if (!isFinite(wn) || wn <= 0) return as_value(true);
337
338 double hn = toNumber(h, getVM(fn));
339 if (!isFinite(hn) || hn <= 0) return as_value(true);
340
341 return as_value(false);
342 }
343
344 as_value
Rectangle_offset(const fn_call & fn)345 Rectangle_offset(const fn_call& fn)
346 {
347 as_object* ptr = ensure<ValidThis>(fn);
348
349 as_value xdelta = fn.nargs > 0 ? fn.arg(0) : as_value();
350 as_value ydelta = fn.nargs > 1 ? fn.arg(1) : as_value();
351
352 as_value x = getMember(*ptr, NSV::PROP_X);
353 newAdd(x, xdelta, getVM(fn));
354 ptr->set_member(NSV::PROP_X, x);
355
356 as_value y = getMember(*ptr, NSV::PROP_Y);
357 newAdd(y, ydelta, getVM(fn));
358 ptr->set_member(NSV::PROP_Y, y);
359
360 return as_value();
361 }
362
363 as_value
Rectangle_offsetPoint(const fn_call & fn)364 Rectangle_offsetPoint(const fn_call& fn)
365 {
366 as_object* ptr = ensure<ValidThis>(fn);
367
368 as_object* arg = (fn.nargs > 0) ? toObject(fn.arg(0), getVM(fn)) : nullptr;
369 if (!arg) return as_value();
370
371 as_value xdelta = getMember(*arg, NSV::PROP_X);
372 as_value ydelta = getMember(*arg, NSV::PROP_Y);
373
374 as_value x = getMember(*ptr, NSV::PROP_X);
375 newAdd(x, xdelta, getVM(fn));
376 ptr->set_member(NSV::PROP_X, x);
377
378 as_value y = getMember(*ptr, NSV::PROP_Y);
379 newAdd(y, ydelta, getVM(fn));
380 ptr->set_member(NSV::PROP_Y, y);
381
382 return as_value();
383 }
384
385 as_value
Rectangle_setEmpty(const fn_call & fn)386 Rectangle_setEmpty(const fn_call& fn)
387 {
388 as_object* ptr = ensure<ValidThis>(fn);
389 ptr->set_member(NSV::PROP_X, 0.0);
390 ptr->set_member(NSV::PROP_Y, 0.0);
391 ptr->set_member(NSV::PROP_WIDTH, 0.0);
392 ptr->set_member(NSV::PROP_HEIGHT, 0.0);
393 return as_value();
394 }
395
396 as_value
Rectangle_toString(const fn_call & fn)397 Rectangle_toString(const fn_call& fn)
398 {
399 as_object* ptr = ensure<ValidThis>(fn);
400
401 as_value x = getMember(*ptr, NSV::PROP_X);
402 as_value y = getMember(*ptr, NSV::PROP_Y);
403 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
404 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
405
406 VM& vm = getVM(fn);
407
408 as_value ret("(x=");
409 newAdd(ret, x, vm);
410 newAdd(ret, ", y=", vm);
411 newAdd(ret, y, vm);
412 newAdd(ret, ", w=", vm);
413 newAdd(ret, w, vm);
414 newAdd(ret, ", h=", vm);
415 newAdd(ret, h, vm);
416 newAdd(ret, ")", vm);
417
418 return ret;
419 }
420
421 as_value
Rectangle_union(const fn_call & fn)422 Rectangle_union(const fn_call& fn)
423 {
424 as_object* ptr = ensure<ValidThis>(fn);
425 UNUSED(ptr);
426 LOG_ONCE(log_unimpl(__FUNCTION__) );
427 return as_value();
428 }
429
430 as_value
Rectangle_bottom(const fn_call & fn)431 Rectangle_bottom(const fn_call& fn)
432 {
433 as_object* ptr = ensure<ValidThis>(fn);
434
435 if (!fn.nargs) {
436 as_value b = getMember(*ptr, NSV::PROP_Y);
437 as_value height = getMember(*ptr, NSV::PROP_HEIGHT);
438 newAdd(b, height, getVM(fn));
439 return b;
440 }
441 as_value y = getMember(*ptr, NSV::PROP_Y);
442 as_value height = fn.arg(0);
443 subtract(height, y, getVM(fn));
444 ptr->set_member(NSV::PROP_HEIGHT, height);
445
446 return as_value();
447 }
448
449 as_value
Rectangle_bottomRight(const fn_call & fn)450 Rectangle_bottomRight(const fn_call& fn)
451 {
452 as_object* ptr = ensure<ValidThis>(fn);
453
454 if (!fn.nargs) {
455
456 as_value x = getMember(*ptr, NSV::PROP_X);
457 as_value y = getMember(*ptr, NSV::PROP_Y);
458 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
459 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
460
461 VM& vm = getVM(fn);
462 newAdd(x, w, vm);
463 newAdd(y, h, vm);
464
465 as_value point(findObject(fn.env(), "flash.geom.Point"));
466
467 as_function* pointCtor = point.to_function();
468
469 if (!pointCtor) {
470 IF_VERBOSE_ASCODING_ERRORS(
471 log_aserror(_("Failed to construct flash.geom.Point!"));
472 );
473 return as_value();
474 }
475
476 fn_call::Args args;
477 args += x, y;
478
479 return constructInstance(*pointCtor, fn.env(), args);
480 }
481
482 IF_VERBOSE_ASCODING_ERRORS(
483 log_aserror(_("Attempt to set read-only property %s"),
484 "Rectangle.bottomRight");
485 );
486 return as_value();
487
488 }
489
490 as_value
Rectangle_left(const fn_call & fn)491 Rectangle_left(const fn_call& fn)
492 {
493 as_object* ptr = ensure<ValidThis>(fn);
494
495 if (!fn.nargs) {
496 return getMember(*ptr, NSV::PROP_X);
497 }
498 as_value oldx = getMember(*ptr, NSV::PROP_X);
499
500 as_value newx = fn.arg(0);
501 ptr->set_member(NSV::PROP_X, newx);
502
503 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
504
505 VM& vm = getVM(fn);
506 subtract(oldx, newx, vm);
507 newAdd(w, oldx, vm);
508 ptr->set_member(NSV::PROP_WIDTH, w);
509
510 return as_value();
511 }
512
513 as_value
Rectangle_right(const fn_call & fn)514 Rectangle_right(const fn_call& fn)
515 {
516 as_object* ptr = ensure<ValidThis>(fn);
517
518 if (!fn.nargs) {
519 as_value r = getMember(*ptr, NSV::PROP_X);
520 as_value width = getMember(*ptr, NSV::PROP_WIDTH);
521 newAdd(r, width, getVM(fn));
522 return r;
523 }
524
525 as_value x = getMember(*ptr, NSV::PROP_X);
526
527 as_value width = fn.arg(0);
528 subtract(width, x, getVM(fn));
529 ptr->set_member(NSV::PROP_WIDTH, width);
530 return as_value();
531 }
532
533 as_value
Rectangle_size(const fn_call & fn)534 Rectangle_size(const fn_call& fn)
535 {
536 as_object* ptr = ensure<ValidThis>(fn);
537
538 if (!fn.nargs) {
539 as_value w = getMember(*ptr, NSV::PROP_WIDTH);
540 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
541
542 as_function* pointCtor = getClassConstructor(fn, "flash.geom.Point");
543 if (!pointCtor) {
544 IF_VERBOSE_ASCODING_ERRORS(
545 log_aserror(_("Failed to construct flash.geom.Point!"));
546 );
547 return as_value();
548 }
549
550 fn_call::Args args;
551 args += w, h;
552
553 return constructInstance(*pointCtor, fn.env(), args);
554 }
555
556 IF_VERBOSE_ASCODING_ERRORS(
557 log_aserror(_("Attempt to set read-only property %s"),
558 "Rectangle.size");
559 );
560
561 return as_value();
562 }
563
564 as_value
Rectangle_top(const fn_call & fn)565 Rectangle_top(const fn_call& fn)
566 {
567 as_object* ptr = ensure<ValidThis>(fn);
568
569 if (!fn.nargs) {
570 // getter
571 return getMember(*ptr, NSV::PROP_Y);
572 }
573
574 // setter
575 as_value oldy = getMember(*ptr, NSV::PROP_Y);
576
577 as_value newy = fn.arg(0);
578 ptr->set_member(NSV::PROP_Y, newy);
579
580 as_value h = getMember(*ptr, NSV::PROP_HEIGHT);
581
582 VM& vm = getVM(fn);
583 subtract(oldy, newy, vm);
584 newAdd(h, oldy, vm);
585 ptr->set_member(NSV::PROP_HEIGHT, h);
586
587 return as_value();
588 }
589
590 as_value
Rectangle_topLeft(const fn_call & fn)591 Rectangle_topLeft(const fn_call& fn)
592 {
593 as_object* ptr = ensure<ValidThis>(fn);
594
595 // getter
596 if (!fn.nargs) {
597 as_value x = getMember(*ptr, NSV::PROP_X);
598 as_value y = getMember(*ptr, NSV::PROP_Y);
599
600 as_function* pointCtor = getClassConstructor(fn, "flash.geom.Point");
601 if (!pointCtor) {
602 IF_VERBOSE_ASCODING_ERRORS(
603 log_aserror(_("Failed to construct flash.geom.Point!"));
604 );
605 return as_value();
606 }
607
608 fn_call::Args args;
609 args += x, y;
610
611 return constructInstance(*pointCtor, fn.env(), args);
612
613 }
614
615 IF_VERBOSE_ASCODING_ERRORS(
616 log_aserror(_("Attempt to set read-only property %s"),
617 "Rectangle.topLeft");
618 );
619
620 return as_value();
621 }
622
623
624 as_value
Rectangle_ctor(const fn_call & fn)625 Rectangle_ctor(const fn_call& fn)
626 {
627
628 as_object* obj = ensure<ValidThis>(fn);
629
630 if (!fn.nargs) {
631 // TODO: use NSV !
632 const ObjectURI& setEmpty = getURI(getVM(fn), "setEmpty");
633 callMethod(obj, setEmpty);
634 return as_value();
635 }
636
637 // At least one arg
638 obj->set_member(NSV::PROP_X, fn.arg(0));
639 obj->set_member(NSV::PROP_Y, fn.nargs > 1 ? fn.arg(1) : as_value());
640 obj->set_member(NSV::PROP_WIDTH, fn.nargs > 2 ? fn.arg(2) : as_value());
641 obj->set_member(NSV::PROP_HEIGHT, fn.nargs > 3 ? fn.arg(3) : as_value());
642
643 return as_value();
644 }
645
646 as_value
get_flash_geom_rectangle_constructor(const fn_call & fn)647 get_flash_geom_rectangle_constructor(const fn_call& fn)
648 {
649 log_debug("Loading flash.geom.Rectangle class");
650 Global_as& gl = getGlobal(fn);
651 as_object* proto = createObject(gl);
652 attachRectangleInterface(*proto);
653 return gl.createClass(&Rectangle_ctor, proto);
654 }
655
656 } // anonymous namespace
657 } // end of gnash namespace
658