[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] /srv/bzr/gnash/trunk r11125: Add an AS3 MovieClip interfa
From: |
Benjamin Wolsey |
Subject: |
[Gnash-commit] /srv/bzr/gnash/trunk r11125: Add an AS3 MovieClip interface. Move the AS functions into |
Date: |
Tue, 16 Jun 2009 09:30:47 +0200 |
User-agent: |
Bazaar (1.13.1) |
------------------------------------------------------------
revno: 11125
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Tue 2009-06-16 09:30:47 +0200
message:
Add an AS3 MovieClip interface. Move the AS functions into
flash/display/MovieClip_as.cpp (I'm not sure this is a good idea, as
MovieClip currently needs access to the interface objects).
Make AVM2 call super constructors somehow (but not necessarily correctly).
Don't return so much on AVM2 failure; break instead.
Drop bogus global addChild functions.
modified:
libcore/ClassHierarchy.cpp
libcore/DisplayObject.cpp
libcore/DisplayObjectContainer.h
libcore/MovieClip.cpp
libcore/MovieClip.h
libcore/TextField.cpp
libcore/as_object.cpp
libcore/asobj/Global.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.h
libcore/asobj/flash/display/MovieClip_as.cpp
libcore/asobj/flash/display/MovieClip_as.h
libcore/asobj/flash/display/display.am
libcore/vm/Machine.cpp
libcore/vm/VM.h
testsuite/as3/dejagnu.as
------------------------------------------------------------
revno: 10995.2.1
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 07:33:47 +0200
message:
Make DisplayObjectContainer as_object interface available to other classes
(for inheritance). Use DisplayObjectContainer class as implementation.
modified:
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.h
------------------------------------------------------------
revno: 10995.2.2
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 08:48:54 +0200
message:
Move the MovieClip AS interface to display/MovieClip_as.cpp, leaving the
implementation where it is.
Start splitting AS3 and AS2 interface.
modified:
libcore/ClassHierarchy.cpp
libcore/MovieClip.cpp
libcore/MovieClip.h
libcore/asobj/Global.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
libcore/asobj/flash/display/MovieClip_as.cpp
libcore/asobj/flash/display/MovieClip_as.h
libcore/asobj/flash/display/display.am
libcore/vm/VM.h
------------------------------------------------------------
revno: 10995.2.3
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 08:53:55 +0200
message:
Use different ctors for AS2 and AS3 MovieClips.
modified:
libcore/asobj/flash/display/MovieClip_as.cpp
libcore/asobj/flash/display/MovieClip_as.h
------------------------------------------------------------
revno: 10995.2.4
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 09:14:23 +0200
message:
Silence irritating debugging.
modified:
libcore/DisplayObject.cpp
------------------------------------------------------------
revno: 10995.2.5
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 09:14:33 +0200
message:
Add numChildren(), move addChild and addChildAt to where they should be.
modified:
libcore/DisplayObjectContainer.h
libcore/asobj/Global.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
------------------------------------------------------------
revno: 10995.2.6
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Thu 2009-06-04 13:51:18 +0200
message:
Minor fixes.
modified:
libcore/TextField.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
------------------------------------------------------------
revno: 10995.2.7
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Mon 2009-06-15 11:01:54 +0200
message:
Logging.
modified:
libcore/abc_function.cpp
libcore/as_object.cpp
libcore/asobj/flash/display/MovieClip_as.cpp
------------------------------------------------------------
revno: 11124.1.1
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 07:42:44 +0200
message:
Add AS3 interface for MovieClip and DisplayObjectContainer.
modified:
libcore/ClassHierarchy.cpp
libcore/DisplayObject.cpp
libcore/DisplayObjectContainer.h
libcore/MovieClip.cpp
libcore/MovieClip.h
libcore/TextField.cpp
libcore/as_object.cpp
libcore/asobj/Global.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
libcore/asobj/flash/display/DisplayObjectContainer_as.h
libcore/asobj/flash/display/MovieClip_as.cpp
libcore/asobj/flash/display/MovieClip_as.h
libcore/asobj/flash/display/display.am
libcore/vm/Machine.cpp
libcore/vm/VM.h
------------------------------------------------------------
revno: 11124.1.2
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 07:45:41 +0200
message:
Silence debugging.
modified:
libcore/as_object.cpp
------------------------------------------------------------
revno: 11124.1.3
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 08:35:15 +0200
message:
Minor fix.
modified:
testsuite/as3/dejagnu.as
------------------------------------------------------------
revno: 11124.1.4
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 08:45:47 +0200
message:
Get the super class ctor called somehow.
modified:
libcore/vm/Machine.cpp
------------------------------------------------------------
revno: 11124.1.5
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 08:51:59 +0200
message:
Useful debugging.
modified:
libcore/vm/Machine.cpp
------------------------------------------------------------
revno: 11124.1.6
committer: Benjamin Wolsey <address@hidden>
branch nick: test
timestamp: Tue 2009-06-16 08:52:04 +0200
message:
Don't try creating a MovieClip for now, or it will crash.
modified:
libcore/asobj/flash/display/MovieClip_as.cpp
=== modified file 'libcore/ClassHierarchy.cpp'
--- a/libcore/ClassHierarchy.cpp 2009-06-12 19:37:55 +0000
+++ b/libcore/ClassHierarchy.cpp 2009-06-16 05:42:44 +0000
@@ -42,6 +42,7 @@
#include "Math_as.h"
#include "Namespace_as.h"
#include "flash/ui/Mouse_as.h"
+#include "flash/display/MovieClip_as.h"
#include "MovieClipLoader.h"
#include "movie_definition.h"
#include "NetConnection_as.h"
=== modified file 'libcore/DisplayObject.cpp'
--- a/libcore/DisplayObject.cpp 2009-06-03 16:05:40 +0000
+++ b/libcore/DisplayObject.cpp 2009-06-04 07:14:23 +0000
@@ -1297,8 +1297,8 @@
// must be an as-referenceable
// DisplayObject created using 'new'
// like, new MovieClip, new Video, new
TextField...
- log_debug("DisplayObject %p (%s) doesn't have a
parent and "
- "is not a Movie", ch, typeName(*ch));
+ //log_debug("DisplayObject %p (%s) doesn't have
a parent and "
+ // "is not a Movie", ch, typeName(*ch));
ss << "<no parent, depth" << ch->get_depth() <<
">";
path.push_back(ss.str());
}
=== modified file 'libcore/DisplayObjectContainer.h'
--- a/libcore/DisplayObjectContainer.h 2009-06-03 13:34:35 +0000
+++ b/libcore/DisplayObjectContainer.h 2009-06-04 07:14:33 +0000
@@ -62,7 +62,7 @@
//
/// @param index The depth from which to remove a DisplayObject.
/// @return The removed DisplayObject (reflects the AS return)
- virtual DisplayObject* removeChildAt(int index);
+ DisplayObject* removeChildAt(int index);
/// Remove the specified child DisplayObject.
//
@@ -73,7 +73,7 @@
//
/// @param obj The DisplayObject to remove.
/// @return The removed DisplayObject (reflects the AS return)
- virtual DisplayObject* removeChild(DisplayObject* obj);
+ DisplayObject* removeChild(DisplayObject* obj);
/// Add a child DisplayObject at the next suitable index (AS2: depth).
//
@@ -84,7 +84,7 @@
//
/// @param obj The DisplayObject to add.
/// @return The added DisplayObject (reflects the AS return)
- virtual DisplayObject* addChild(DisplayObject* obj);
+ DisplayObject* addChild(DisplayObject* obj);
/// Add a child DisplayObject at the specified index (AS2: depth).
//
@@ -96,7 +96,11 @@
/// @param obj The DisplayObject to add.
/// @param index The index (depth) at which to add the DisplayObject.
/// @return The added DisplayObject (reflects the AS return)
- virtual DisplayObject* addChildAt(DisplayObject* obj, int index);
+ DisplayObject* addChildAt(DisplayObject* obj, int index);
+
+ size_t numChildren() const {
+ return _displayList.size();
+ }
#ifdef USE_SWFTREE
// Override to append display list info, see dox in DisplayObject.h
=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp 2009-06-15 14:53:11 +0000
+++ b/libcore/MovieClip.cpp 2009-06-16 05:42:44 +0000
@@ -64,6 +64,9 @@
#include "InteractiveObject.h"
#include "DisplayObjectContainer.h"
+// TODO: get rid of this include.
+#include "flash/display/MovieClip_as.h"
+
#include <vector>
#include <string>
#include <algorithm> // for std::swap
@@ -90,73 +93,8 @@
//
//#define DEBUG_MOUSE_ENTITY_FINDING 1
-// Forward declarations
-namespace {
- as_object* getMovieClipInterface();
- void attachMovieClipInterface(as_object& o);
- void attachMovieClipProperties(DisplayObject& o);
-
- as_value movieclip_transform(const fn_call& fn);
- as_value movieclip_scale9Grid(const fn_call& fn);
- as_value movieclip_attachVideo(const fn_call& fn);
- as_value movieclip_attachAudio(const fn_call& fn);
- as_value movieclip_attachMovie(const fn_call& fn);
- as_value movieclip_unloadMovie(const fn_call& fn);
- as_value movieclip_loadMovie(const fn_call& fn);
- as_value movieclip_getURL(const fn_call& fn);
- as_value movieclip_ctor(const fn_call& fn);
- as_value movieclip_attachBitmap(const fn_call& fn);
- as_value movieclip_beginBitmapFill(const fn_call& fn);
- as_value movieclip_createEmptyMovieClip(const fn_call& fn);
- as_value movieclip_removeMovieClip(const fn_call& fn);
- as_value movieclip_createTextField(const fn_call& fn);
- as_value movieclip_curveTo(const fn_call& fn);
- as_value movieclip_beginFill(const fn_call& fn);
- as_value movieclip_prevFrame(const fn_call& fn);
- as_value movieclip_nextFrame(const fn_call& fn);
- as_value movieclip_endFill(const fn_call& fn);
- as_value movieclip_clear(const fn_call& fn);
- as_value movieclip_lineStyle(const fn_call& fn);
- as_value movieclip_lineTo(const fn_call& fn);
- as_value movieclip_moveTo(const fn_call& fn);
- as_value movieclip_beginGradientFill(const fn_call& fn);
- as_value movieclip_stopDrag(const fn_call& fn);
- as_value movieclip_startDrag(const fn_call& fn);
- as_value movieclip_removeMovieClip(const fn_call& fn);
- as_value movieclip_gotoAndStop(const fn_call& fn);
- as_value movieclip_duplicateMovieClip(const fn_call& fn);
- as_value movieclip_gotoAndPlay(const fn_call& fn);
- as_value movieclip_stop(const fn_call& fn);
- as_value movieclip_play(const fn_call& fn);
- as_value movieclip_setMask(const fn_call& fn);
- as_value movieclip_getDepth(const fn_call& fn);
- as_value movieclip_getBytesTotal(const fn_call& fn);
- as_value movieclip_getBytesLoaded(const fn_call& fn);
- as_value movieclip_getBounds(const fn_call& fn);
- as_value movieclip_hitTest(const fn_call& fn);
- as_value movieclip_globalToLocal(const fn_call& fn);
- as_value movieclip_localToGlobal(const fn_call& fn);
- as_value movieclip_swapDepths(const fn_call& fn);
- as_value movieclip_scrollRect(const fn_call& fn);
- as_value movieclip_getInstanceAtDepth(const fn_call& fn);
- as_value movieclip_getNextHighestDepth(const fn_call& fn);
- as_value movieclip_getTextSnapshot(const fn_call& fn);
- as_value movieclip_tabIndex(const fn_call& fn);
- as_value movieclip_opaqueBackground(const fn_call& fn);
- as_value movieclip_filters(const fn_call& fn);
- as_value movieclip_forceSmoothing(const fn_call& fn);
- as_value movieclip_cacheAsBitmap(const fn_call& fn);
- as_value movieclip_lineGradientStyle(const fn_call& fn);
- as_value movieclip_getRect(const fn_call& fn);
- as_value movieclip_meth(const fn_call& fn);
- as_value movieclip_getSWFVersion(const fn_call& fn);
- as_value movieclip_loadVariables(const fn_call& fn);
-
-}
-
/// Anonymous namespace for module-private definitions
-namespace
-{
+namespace {
/// ConstructEvent, used for queuing construction
//
@@ -494,13 +432,16 @@
{
assert(_swf);
- set_prototype(getMovieClipInterface());
+ if (!isAS3(getVM())) {
+ set_prototype(getMovieClipAS2Interface());
+ attachMovieClipAS2Properties(*this);
+ }
+ else {
+ set_prototype(getMovieClipAS3Interface());
+ }
_environment.set_target(this);
- // TODO: have the 'MovieClip' constructor take care of this !
- attachMovieClipProperties(*this);
-
}
MovieClip::~MovieClip()
@@ -761,7 +702,8 @@
}
boost::intrusive_ptr<DisplayObject>
-MovieClip::add_textfield(const std::string& name, int depth, int x, int y,
float width, float height)
+MovieClip::add_textfield(const std::string& name, int depth, int x, int y,
+ float width, float height)
{
// Set textfield bounds
@@ -777,7 +719,8 @@
// Set _x and _y
SWFMatrix txt_matrix;
txt_matrix.set_translation(pixelsToTwips(x), pixelsToTwips(y));
- txt_char->setMatrix(txt_matrix, true); // update caches (altought
shouldn't be needed as we only set translation)
+ // update caches (although shouldn't be needed as we only set translation)
+ txt_char->setMatrix(txt_matrix, true);
// Here we add the DisplayObject to the displayList.
_displayList.placeDisplayObject(txt_char.get(), depth);
@@ -808,9 +751,6 @@
newmovieclip->setDynamic();
- //if ( initObject ) newmovieclip->copyProperties(*initObject);
- //else newmovieclip->copyProperties(*this);
-
// Copy event handlers from movieclip
// We should not copy 'm_action_buffer' since the
// 'm_method' already contains it
@@ -2703,2488 +2643,4 @@
_playState = s;
}
-
-void
-movieclip_class_init(as_object& global)
-{
- // This is going to be the global MovieClip "class"/"function"
- static boost::intrusive_ptr<builtin_function> cl=NULL;
-
- if ( cl == NULL )
- {
- cl = new builtin_function(&movieclip_ctor, getMovieClipInterface());
- global.getVM().addStatic(cl.get());
- }
-
- // Register _global.MovieClip
- global.init_member("MovieClip", cl.get());
-}
-
-
-//---------------------
-// MovieClip interface
-//---------------------
-
-namespace {
-
-/// Properties (and/or methods) *inherited* by MovieClip instances
-void
-attachMovieClipInterface(as_object& o)
-{
- VM& vm = o.getVM();
-
- o.init_member("attachMovie", vm.getNative(900, 0));
- o.init_member("swapDepths", vm.getNative(900, 1));
- o.init_member("localToGlobal", vm.getNative(900, 2));
- o.init_member("globalToLocal", vm.getNative(900, 3));
- o.init_member("hitTest", vm.getNative(900, 4));
- o.init_member("getBounds", vm.getNative(900, 5));
- o.init_member("getBytesTotal", vm.getNative(900, 6));
- o.init_member("getBytesLoaded", vm.getNative(900, 7));
- o.init_member("play", vm.getNative(900, 12));
- o.init_member("stop", vm.getNative(900, 13));
- o.init_member("nextFrame", vm.getNative(900, 14));
- o.init_member("prevFrame", vm.getNative(900, 15));
- o.init_member("gotoAndPlay", vm.getNative(900, 16));
- o.init_member("gotoAndStop", vm.getNative(900, 17));
- o.init_member("duplicateMovieClip", vm.getNative(900, 18));
- o.init_member("removeMovieClip", vm.getNative(900, 19));
- o.init_member("startDrag", vm.getNative(900, 20));
- o.init_member("stopDrag", vm.getNative(900, 21));
- o.init_member("loadMovie", new builtin_function(movieclip_loadMovie));
- o.init_member("loadVariables", new builtin_function(
- movieclip_loadVariables));
- o.init_member("unloadMovie", new builtin_function(
- movieclip_unloadMovie));
- o.init_member("getURL", new builtin_function(movieclip_getURL));
- o.init_member("getSWFVersion", new builtin_function(
- movieclip_getSWFVersion));
- o.init_member("meth", new builtin_function(movieclip_meth));
- o.init_member("enabled", true);
- o.init_member("useHandCursor", true);
- o.init_property("_lockroot", &MovieClip::lockroot_getset,
- &MovieClip::lockroot_getset);
- o.init_member("beginBitmapFill", new builtin_function(
- movieclip_beginBitmapFill));
- o.init_member("getRect", new builtin_function(
- movieclip_getRect));
- o.init_member("lineGradientStyle", new builtin_function(
- movieclip_lineGradientStyle));
- o.init_member("attachBitmap", new builtin_function(
- movieclip_attachBitmap));
- o.init_property("blendMode", &DisplayObject::blendMode,
- &DisplayObject::blendMode);
- o.init_property("cacheAsBitmap", &movieclip_cacheAsBitmap,
- &movieclip_cacheAsBitmap);
- o.init_property("filters", &movieclip_filters, &movieclip_filters);
- o.init_property("forceSmoothing", &movieclip_forceSmoothing,
- &movieclip_forceSmoothing);
- o.init_property("opaqueBackground", &movieclip_opaqueBackground,
- &movieclip_opaqueBackground);
- o.init_property("scale9Grid", &movieclip_scale9Grid,
- movieclip_scale9Grid);
- o.init_property("scrollRect", &movieclip_scrollRect,
- &movieclip_scrollRect);
- o.init_property("tabIndex", &movieclip_tabIndex, &movieclip_tabIndex);
- o.init_property("transform", &movieclip_transform,
- &movieclip_transform);
-
- const int swf6Flags = as_prop_flags::dontDelete |
- as_prop_flags::dontEnum |
- as_prop_flags::onlySWF6Up;
-
- o.init_member("attachAudio", vm.getNative(900, 8), swf6Flags);
- o.init_member("attachVideo", vm.getNative(900, 9), swf6Flags);
- o.init_member("getDepth", vm.getNative(900, 10), swf6Flags);
- o.init_member("setMask", vm.getNative(900, 11), swf6Flags);
- o.init_member("createEmptyMovieClip", vm.getNative(901, 0), swf6Flags);
- o.init_member("beginFill", vm.getNative(901, 1), swf6Flags);
- o.init_member("beginGradientFill", vm.getNative(901, 2), swf6Flags);
- o.init_member("moveTo", vm.getNative(901, 3), swf6Flags);
- o.init_member("lineTo", vm.getNative(901, 4), swf6Flags);
- o.init_member("curveTo", vm.getNative(901, 5), swf6Flags);
- o.init_member("lineStyle", vm.getNative(901, 6), swf6Flags);
- o.init_member("endFill", vm.getNative(901, 7), swf6Flags);
- o.init_member("clear", vm.getNative(901, 8), swf6Flags);
- o.init_member("createTextField", vm.getNative(104, 200), swf6Flags);
- o.init_member("getTextSnapshot",
- new builtin_function(movieclip_getTextSnapshot), swf6Flags);
-
- const int swf7Flags = as_prop_flags::dontDelete |
- as_prop_flags::dontEnum |
- as_prop_flags::onlySWF7Up;
-
- o.init_member("getNextHighestDepth", new builtin_function(
- movieclip_getNextHighestDepth), swf7Flags);
- o.init_member("getInstanceAtDepth", new builtin_function(
- movieclip_getInstanceAtDepth), swf7Flags);
-
-}
-
-void
-registerNatives(VM& vm)
-{
- // Natives are always here (at least in swf5 I guess)
- vm.registerNative(movieclip_attachMovie, 900, 0);
- // TODO: generalize to DisplayObject::swapDepths_method ?
- vm.registerNative(movieclip_swapDepths, 900, 1);
- vm.registerNative(movieclip_localToGlobal, 900, 2);
- vm.registerNative(movieclip_globalToLocal, 900, 3);
- vm.registerNative(movieclip_hitTest, 900, 4);
- vm.registerNative(movieclip_getBounds, 900, 5);
- vm.registerNative(movieclip_getBytesTotal, 900, 6);
- vm.registerNative(movieclip_getBytesLoaded, 900, 7);
- vm.registerNative(movieclip_attachAudio, 900, 8);
- vm.registerNative(movieclip_attachVideo, 900, 9);
- // TODO: generalize to DisplayObject::getDepth_method ?
- vm.registerNative(movieclip_getDepth, 900, 10);
- vm.registerNative(movieclip_setMask, 900, 11);
- vm.registerNative(movieclip_play, 900, 12);
- vm.registerNative(movieclip_stop, 900, 13);
- vm.registerNative(movieclip_nextFrame, 900, 14);
- vm.registerNative(movieclip_prevFrame, 900, 15);
- vm.registerNative(movieclip_gotoAndPlay, 900, 16);
- vm.registerNative(movieclip_gotoAndStop, 900, 17);
- vm.registerNative(movieclip_duplicateMovieClip, 900, 18);
- vm.registerNative(movieclip_removeMovieClip, 900, 19);
- vm.registerNative(movieclip_startDrag, 900, 20);
- vm.registerNative(movieclip_stopDrag, 900, 21);
- vm.registerNative(movieclip_createEmptyMovieClip, 901, 0);
- vm.registerNative(movieclip_beginFill, 901, 1);
- vm.registerNative(movieclip_beginGradientFill, 901, 2);
- vm.registerNative(movieclip_moveTo, 901, 3);
- vm.registerNative(movieclip_lineTo, 901, 4);
- vm.registerNative(movieclip_curveTo, 901, 5);
- vm.registerNative(movieclip_lineStyle, 901, 6);
- vm.registerNative(movieclip_endFill, 901, 7);
- vm.registerNative(movieclip_clear, 901, 8);
-
- vm.registerNative(movieclip_createTextField, 104, 200);
-
-}
-
-as_value
-movieclip_play(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
- return as_value();
-}
-
-as_value
-movieclip_stop(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
-
- return as_value();
-}
-
-
-//removeMovieClip() : Void
-as_value
-movieclip_removeMovieClip(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- movieclip->removeMovieClip();
- return as_value();
-}
-
-
-as_value
-movieclip_cacheAsBitmap(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE( log_unimpl(_("MovieClip.cacheAsBitmap()")) );
- return as_value();
-}
-
-
-as_value
-movieclip_filters(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.filters()")));
- return as_value();
-}
-
-
-as_value
-movieclip_forceSmoothing(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.forceSmoothing()")));
- return as_value();
-}
-
-
-as_value
-movieclip_opaqueBackground(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.opaqueBackground()")));
- return as_value();
-}
-
-
-as_value
-movieclip_scale9Grid(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.scale9Grid()")));
- return as_value();
-}
-
-
-as_value
-movieclip_scrollRect(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.scrollRect()")));
- return as_value();
-}
-
-
-as_value
-movieclip_tabIndex(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
- LOG_ONCE(log_unimpl(_("MovieClip.tabIndex()")));
- return as_value();
-}
-
-
-// attachMovie(idName:String, newName:String,
-// depth:Number [, initObject:Object]) : MovieClip
-as_value
-movieclip_attachMovie(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 3 || fn.nargs > 4)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("attachMovie called with wrong number of arguments"
- " expected 3 to 4, got (%d) - returning undefined"), fn.nargs);
- );
- return as_value();
- }
-
- // Get exported resource
- const std::string& id_name = fn.arg(0).to_string();
-
- boost::intrusive_ptr<ExportableResource> exported =
- movieclip->get_root()->definition()->get_exported_resource(id_name);
-
- if (!exported)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("attachMovie: '%s': no such exported resource - "
- "returning undefined"), id_name);
- );
- return as_value();
- }
-
- SWF::DefinitionTag* exported_movie =
- dynamic_cast<SWF::DefinitionTag*>(exported.get());
-
- if (!exported_movie)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("attachMovie: exported resource '%s' "
- "is not a DisplayObject definition (%s) -- "
- "returning undefined"), id_name,
- typeid(*(exported.get())).name());
- );
- return as_value();
- }
-
- const std::string& newname = fn.arg(1).to_string();
-
- // Movies should be attachable from -16384 to 2130690045, according to
- // kirupa (http://www.kirupa.com/developer/actionscript/depths2.htm)
- // Tests in misc-ming.all/DepthLimitsTest.c show that 2130690044 is the
- // maximum valid depth.
- const double depth = fn.arg(2).to_number();
-
- // This also checks for overflow, as both numbers are expressible as
- // boost::int32_t.
- if (depth < DisplayObject::lowerAccessibleBound ||
- depth > DisplayObject::upperAccessibleBound)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.attachMovie: invalid depth %d "
- "passed; not attaching"), depth);
- );
- return as_value();
- }
-
- boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
-
- boost::intrusive_ptr<DisplayObject> newch =
- exported_movie->createDisplayObject(movieclip.get(), 0);
-
-#ifndef GNASH_USE_GC
- assert(newch->get_ref_count() > 0);
-#endif // ndef GNASH_USE_GC
-
- newch->set_name(newname);
- newch->setDynamic();
-
- boost::intrusive_ptr<as_object> initObj;
-
- if (fn.nargs > 3 ) {
- initObj = fn.arg(3).to_object();
- if (!initObj) {
- // This is actually a valid thing to do,
- // the documented behaviour is to just NOT
- // initialize the properties in this
- // case.
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Fourth argument of attachMovie doesn't cast to "
- "an object (%s), we'll act as if it wasn't given"),
- fn.arg(3));
- );
- }
- }
-
- // placeDisplayObject() will set depth on newch
- if (!movieclip->attachCharacter(*newch, depthValue, initObj.get()))
- {
- log_error(_("Could not attach DisplayObject at depth %d"), depthValue);
- return as_value();
- }
-
- return as_value(newch.get());
-}
-
-
-// attachAudio(id:Object) : Void
-as_value
-movieclip_attachAudio(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (!fn.nargs)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("MovieClip.attachAudio(): %s", _("missing arguments"));
- );
- return as_value();
- }
-
- as_object* obj = fn.arg(0).to_object().get();
- if ( ! obj )
- {
- std::stringstream ss; fn.dump_args(ss);
- // TODO: find out what to do here
- log_error("MovieClip.attachAudio(%s): first arg doesn't cast to "
- "an object", ss.str());
- return as_value();
- }
-
- NetStream_as* ns = dynamic_cast<NetStream_as*>(obj);
- if ( ! ns )
- {
- std::stringstream ss; fn.dump_args(ss);
- // TODO: find out what to do here
- log_error("MovieClip.attachAudio(%s): first arg doesn't cast to a "
- "NetStream", ss.str());
- return as_value();
- }
-
- ns->setAudioController(movieclip.get());
-
- LOG_ONCE( log_unimpl("MovieClip.attachAudio() - TESTING") );
- return as_value();
-}
-
-
-// MovieClip.attachVideo
-as_value
-movieclip_attachVideo(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(movieclip);
-
- LOG_ONCE( log_unimpl("MovieClip.attachVideo()") );
- return as_value();
-}
-
-
-//createEmptyMovieClip(name:String, depth:Number) : MovieClip
-as_value
-movieclip_createEmptyMovieClip(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs != 2)
- {
- if (fn.nargs < 2)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("createEmptyMovieClip needs "
- "2 args, but %d given,"
- " returning undefined"),
- fn.nargs);
- );
- return as_value();
- }
- else
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("createEmptyMovieClip takes "
- "2 args, but %d given, discarding"
- " the excess"),
- fn.nargs);
- )
- }
- }
-
- // Unlike other MovieClip methods, the depth argument of an empty movie
clip
- // can be any number. All numbers are converted to an int32_t, and are
valid
- // depths even when outside the usual bounds.
- DisplayObject* ch = movieclip->add_empty_movieclip(fn.arg(0).to_string(),
- fn.arg(1).to_int());
- return as_value(ch);
-}
-
-as_value
-movieclip_getDepth(const fn_call& fn)
-{
- // TODO: make this a DisplayObject::getDepth_method function...
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- const int n = movieclip->get_depth();
-
- return as_value(n);
-}
-
-//swapDepths(target:Object|target:Number)
-//
-// Returns void.
-as_value
-movieclip_swapDepths(const fn_call& fn)
-{
-
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- const int this_depth = movieclip->get_depth();
-
- if (fn.nargs < 1)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("%s.swapDepths() needs one arg"),
movieclip->getTarget());
- );
- return as_value();
- }
-
- // Lower bound of source depth below which swapDepth has no effect
- // (below Timeline/static zone)
- if ( this_depth < DisplayObject::lowerAccessibleBound )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss;
- fn.dump_args(ss);
- log_aserror(_("%s.swapDepths(%s): won't swap a clip below "
- "depth %d (%d)"),
- movieclip->getTarget(), ss.str(),
DisplayObject::lowerAccessibleBound,
- this_depth);
- );
- return as_value();
- }
-
- typedef boost::intrusive_ptr<DisplayObject> CharPtr;
- typedef boost::intrusive_ptr<MovieClip> SpritePtr;
-
- SpritePtr this_parent = dynamic_cast<MovieClip*>(
- movieclip->get_parent());
-
- //CharPtr target = NULL;
- int target_depth = 0;
-
- // movieclip.swapDepth(movieclip)
- if ( SpritePtr target_movieclip = fn.arg(0).to_sprite() )
- {
- if ( movieclip == target_movieclip )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("%s.swapDepths(%s): invalid call, swapping to
self?"),
- movieclip->getTarget(), target_movieclip->getTarget());
- );
- return as_value();
- }
-
- SpritePtr target_parent =
- dynamic_cast<MovieClip*>(movieclip->get_parent());
- if ( this_parent != target_parent )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("%s.swapDepths(%s): invalid call, the two "
- "DisplayObjects don't have the same parent"),
- movieclip->getTarget(), target_movieclip->getTarget());
- );
- return as_value();
- }
-
- target_depth = target_movieclip->get_depth();
-
- // Check we're not swapping the our own depth so
- // to avoid unecessary bounds invalidation and immunizing
- // the instance from subsequent PlaceObject tags attempting
- // to transform it.
- if ( movieclip->get_depth() == target_depth )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.swapDepths(%s): ignored, source and "
- "target DisplayObjects have the same depth %d"),
- movieclip->getTarget(), ss.str(), target_depth);
- );
- return as_value();
- }
- }
-
- // movieclip.swapDepth(depth)
- else
- {
- double td = fn.arg(0).to_number();
- if ( isNaN(td) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.swapDepths(%s): first argument invalid "
- "(neither a movieclip nor a number)"),
- movieclip->getTarget(), ss.str());
- );
- return as_value();
- }
-
- target_depth = int(td);
-
- // Check we're not swapping the our own depth so
- // to avoid unecessary bounds invalidation and immunizing
- // the instance from subsequent PlaceObjec tags attempting
- // to transform it.
- if ( movieclip->get_depth() == target_depth )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.swapDepths(%s): ignored, DisplayObject already "
- "at depth %d"),
- movieclip->getTarget(), ss.str(), target_depth);
- );
- return as_value();
- }
-
-
- // TODO : check other kind of validities ?
-
-
- }
-
- if ( this_parent )
- {
- this_parent->swapDepths(movieclip.get(), target_depth);
- }
- else
- {
- movie_root& root = movieclip->getVM().getRoot();
- root.swapLevels(movieclip, target_depth);
- return as_value();
- }
-
- return as_value();
-
-}
-
-// TODO: wrap the functionality in a MovieClip method
-// and invoke it from here, this should only be a wrapper
-//
-//duplicateMovieClip(name:String, depth:Number, [initObject:Object]) :
MovieClip
-as_value
-movieclip_duplicateMovieClip(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 2)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.duplicateMovieClip() needs 2 or 3 args"));
- );
- return as_value();
- }
-
- const std::string& newname = fn.arg(0).to_string();
-
- // Depth as in attachMovie
- const double depth = fn.arg(1).to_number();
-
- // This also checks for overflow, as both numbers are expressible as
- // boost::int32_t.
- if (depth < DisplayObject::lowerAccessibleBound ||
- depth > DisplayObject::upperAccessibleBound)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.duplicateMovieClip: "
- "invalid depth %d passed; not duplicating"), depth);
- );
- return as_value();
- }
-
- boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
-
- boost::intrusive_ptr<MovieClip> ch;
-
- // Copy members from initObject
- if (fn.nargs == 3)
- {
- boost::intrusive_ptr<as_object> initObject = fn.arg(2).to_object();
- ch = movieclip->duplicateMovieClip(newname, depthValue,
- initObject.get());
- }
- else
- {
- ch = movieclip->duplicateMovieClip(newname, depthValue);
- }
-
- return as_value(ch.get());
-}
-
-as_value
-movieclip_gotoAndPlay(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 1)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("movieclip_goto_and_play needs one arg"));
- );
- return as_value();
- }
-
- size_t frame_number;
- if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
- {
- // No dice.
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("movieclip_goto_and_play('%s') -- invalid frame"),
- fn.arg(0));
- );
- return as_value();
- }
-
- // Convert to 0-based
- movieclip->goto_frame(frame_number);
- movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
- return as_value();
-}
-
-as_value movieclip_gotoAndStop(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 1)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("movieclip_goto_and_stop needs one arg"));
- );
- return as_value();
- }
-
- size_t frame_number;
- if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
- {
- // No dice.
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("movieclip_goto_and_stop('%s') -- invalid frame"),
- fn.arg(0));
- );
- return as_value();
- }
-
- // Convert to 0-based
- movieclip->goto_frame(frame_number);
- movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
- return as_value();
-}
-
-as_value movieclip_nextFrame(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- const size_t frame_count = movieclip->get_frame_count();
- const size_t current_frame = movieclip->get_current_frame();
- if (current_frame < frame_count)
- {
- movieclip->goto_frame(current_frame + 1);
- }
- movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
- return as_value();
-}
-
-as_value
-movieclip_prevFrame(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- const size_t current_frame = movieclip->get_current_frame();
- if (current_frame > 0)
- {
- movieclip->goto_frame(current_frame - 1);
- }
- movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
- return as_value();
-}
-
-as_value
-movieclip_getBytesLoaded(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(movieclip->get_bytes_loaded());
-}
-
-as_value
-movieclip_getBytesTotal(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- // @@ horrible uh ?
- return as_value(movieclip->get_bytes_total());
-}
-
-// MovieClip.loadMovie(url:String [,variables:String]).
-//
-// Returns 1 for "get", 2 for "post", and otherwise 0. Case-insensitive.
-// This *always* calls MovieClip.meth.
-as_value
-movieclip_loadMovie(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- as_value val;
- if (fn.nargs > 1) {
- val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
- }
- else val = movieclip->callMethod(NSV::PROP_METH);
-
- if (fn.nargs < 1) // url
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.loadMovie() "
- "expected 1 or 2 args, got %d - returning undefined"),
- fn.nargs);
- );
- return as_value();
- }
-
- const std::string& urlstr = fn.arg(0).to_string();
- if (urlstr.empty())
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("First argument of MovieClip.loadMovie(%s) "
- "evaluates to an empty string - "
- "returning undefined"),
- ss.str());
- );
- return as_value();
- }
-
- movie_root& mr = movieclip->getVM().getRoot();
- std::string target = movieclip->getTarget();
-
- // TODO: if GET/POST should send variables of *this* movie,
- // no matter if the target will be replaced by another movie !!
- const MovieClip::VariablesMethod method =
- static_cast<MovieClip::VariablesMethod>(val.to_int());
-
- std::string data;
-
- // This is just an optimization if we aren't going
- // to send the data anyway. It might be wrong, though.
- if (method != MovieClip::METHOD_NONE)
- {
- movieclip->getURLEncodedVars(data);
- }
-
- mr.loadMovie(urlstr, target, data, method);
-
- return as_value();
-}
-
-// my_mc.loadVariables(url:String [, variables:String]) : Void
-as_value
-movieclip_loadVariables(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- // This always calls MovieClip.meth, even when there are no
- // arguments.
- as_value val;
- if (fn.nargs > 1)
- {
- val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
- }
- else val = movieclip->callMethod(NSV::PROP_METH);
-
- if (fn.nargs < 1) // url
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.loadVariables() "
- "expected 1 or 2 args, got %d - returning undefined"),
- fn.nargs);
- );
- return as_value();
- }
-
- const std::string& urlstr = fn.arg(0).to_string();
- if (urlstr.empty())
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("First argument passed to MovieClip.loadVariables(%s) "
- "evaluates to an empty string - "
- "returning undefined"),
- ss.str());
- );
- return as_value();
- }
-
- const MovieClip::VariablesMethod method =
- static_cast<MovieClip::VariablesMethod>(val.to_int());
-
- movieclip->loadVariables(urlstr, method);
- log_debug("MovieClip.loadVariables(%s) - TESTING ", urlstr);
-
- return as_value();
-}
-
-// my_mc.unloadMovie() : Void
-as_value
-movieclip_unloadMovie(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- movieclip->unloadMovie();
-
- return as_value();
-}
-
-as_value
-movieclip_hitTest(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- switch (fn.nargs)
- {
- case 1: // target
- {
- const as_value& tgt_val = fn.arg(0);
- DisplayObject* target = fn.env().find_target(tgt_val.to_string());
- if ( ! target )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Can't find hitTest target %s"),
- tgt_val);
- );
- return as_value();
- }
-
- rect thisbounds = movieclip->getBounds();
- SWFMatrix thismat = movieclip->getWorldMatrix();
- thismat.transform(thisbounds);
-
- rect tgtbounds = target->getBounds();
- SWFMatrix tgtmat = target->getWorldMatrix();
- tgtmat.transform(tgtbounds);
-
- return thisbounds.getRange().intersects(tgtbounds.getRange());
-
- break;
- }
-
- case 2: // x, y
- {
- boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
- boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
-
- return movieclip->pointInBounds(x, y);
- }
-
- case 3: // x, y, shapeFlag
- {
- boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
- boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
- bool shapeFlag = fn.arg(2).to_bool();
-
- if ( ! shapeFlag ) return movieclip->pointInBounds(x, y);
- else return movieclip->pointInHitableShape(x, y);
- }
-
- default:
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("hitTest() called with %u args"),
- fn.nargs);
- );
- break;
- }
- }
-
- return as_value();
-
-}
-
-as_value
-movieclip_createTextField(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 6) // name, depth, x, y, width, height
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("createTextField called with %d args, "
- "expected 6 - returning undefined"), fn.nargs);
- );
- return as_value();
- }
-
- std::string txt_name = fn.arg(0).to_string();
-
- int txt_depth = fn.arg(1).to_int();
-
- int txt_x = fn.arg(2).to_int();
-
- int txt_y = fn.arg(3).to_int();
-
- int txt_width = fn.arg(4).to_int();
- if ( txt_width < 0 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("createTextField: negative width (%d)"
- " - reverting sign"), txt_width);
- );
- txt_width = -txt_width;
- }
-
- int txt_height = fn.arg(5).to_int();
- if ( txt_height < 0 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("createTextField: negative height (%d)"
- " - reverting sign"), txt_height);
- );
- txt_height = -txt_height;
- }
-
- boost::intrusive_ptr<DisplayObject> txt =
movieclip->add_textfield(txt_name,
- txt_depth, txt_x, txt_y, txt_width, txt_height);
-
- // createTextField returns void, it seems
- if ( movieclip->getVM().getSWFVersion() > 7 ) return as_value(txt.get());
- else return as_value();
-}
-
-//getNextHighestDepth() : Number
-as_value
-movieclip_getNextHighestDepth(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- int nextdepth = movieclip->getNextHighestDepth();
- return as_value(static_cast<double>(nextdepth));
-}
-
-//getInstanceAtDepth(depth:Number) : MovieClip
-as_value
-movieclip_getInstanceAtDepth(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> mc = ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 1)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("MovieClip.getInstanceAtDepth(): missing depth argument");
- );
- return as_value();
- }
-
- int depth = fn.arg(0).to_int();
- boost::intrusive_ptr<DisplayObject> ch =
mc->getDisplayObjectAtDepth(depth);
-
- // we want 'undefined', not 'null'
- if (!ch) return as_value();
- return as_value(ch.get());
-}
-
-/// MovieClip.getURL(url:String[, window:String[, method:String]])
-//
-/// Tested manually to function as a method of any as_object. Hard to
-/// test automatically as it doesn't return anything and only has external
-/// side-effects.
-/// Returns void.
-as_value
-movieclip_getURL(const fn_call& fn)
-{
- boost::intrusive_ptr<as_object> movieclip =
- ensureType<as_object>(fn.this_ptr);
-
- std::string urlstr;
- std::string target;
-
- as_value val;
- if (fn.nargs > 2)
- {
- val = movieclip->callMethod(NSV::PROP_METH, fn.arg(2));
- }
- else val = movieclip->callMethod(NSV::PROP_METH);
-
- switch (fn.nargs)
- {
- case 0:
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("No arguments passed to MovieClip.getURL()"));
- );
- return as_value();
- }
- default:
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream os;
- fn.dump_args(os);
- log_aserror(_("MovieClip.getURL(%s): extra arguments "
- "dropped"), os.str());
- );
- }
- case 3:
- // This argument has already been handled.
- case 2:
- target = fn.arg(1).to_string();
- case 1:
- urlstr = fn.arg(0).to_string();
- break;
- }
-
-
- MovieClip::VariablesMethod method =
- static_cast<MovieClip::VariablesMethod>(val.to_int());
-
- std::string vars;
-
- if (method != MovieClip::METHOD_NONE) {
- // Get encoded vars.
- movieclip->getURLEncodedVars(vars);
- }
-
- movie_root& m = movieclip->getVM().getRoot();
-
- m.getURL(urlstr, target, vars, method);
-
- return as_value();
-}
-
-// getSWFVersion() : Number
-as_value
-movieclip_getSWFVersion(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(movieclip->getSWFVersion());
-}
-
-// MovieClip.meth(<string>) : Number
-//
-// Parses case-insensitive "get" and "post" into 1 and 2, 0 anything else
-//
-as_value
-movieclip_meth(const fn_call& fn)
-{
-
- if (!fn.nargs) return as_value(MovieClip::METHOD_NONE);
-
- const as_value& v = fn.arg(0);
- boost::intrusive_ptr<as_object> o = v.to_object();
- if ( ! o )
- {
- log_debug(_("meth(%s): first argument doesn't cast to object"), v);
- return as_value(MovieClip::METHOD_NONE);
- }
-
- as_value lc = o->callMethod(NSV::PROP_TO_LOWER_CASE);
-
- std::string s = lc.to_string();
-
- if (s == "get") return as_value(MovieClip::METHOD_GET);
- if (s == "post") return as_value(MovieClip::METHOD_POST);
- return as_value(MovieClip::METHOD_NONE);
-}
-
-
-// getTextSnapshot() : TextSnapshot
-as_value
-movieclip_getTextSnapshot(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> obj = ensureType<MovieClip>(fn.this_ptr);
-
- // If not found, construction fails.
- as_value textSnapshot(fn.env().find_object("TextSnapshot"));
-
- boost::intrusive_ptr<as_function> tsCtor = textSnapshot.to_as_function();
-
- if (!tsCtor) {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("MovieClip.getTextSnapshot: failed to construct "
- "TextSnapshot (object probably overridden)");
- );
- return as_value();
- }
-
- // Construct a flash.geom.Transform object with "this" as argument.
- std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
- args->push_back(obj.get());
-
- boost::intrusive_ptr<as_object> ts =
- tsCtor->constructInstance(fn.env(), args);
-
- return as_value(ts.get());
-}
-
-
-// getBounds(targetCoordinateSpace:Object) : Object
-as_value
-movieclip_getBounds(const fn_call& fn)
-{
- boost::intrusive_ptr<DisplayObject> movieclip =
- ensureType<DisplayObject>(fn.this_ptr);
-
- rect bounds = movieclip->getBounds();
-
- if ( fn.nargs > 0 )
- {
- DisplayObject* target = fn.arg(0).toDisplayObject();
- if ( ! target )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.getBounds(%s): invalid call, first "
- "arg must be a DisplayObject"),
- fn.arg(0));
- );
- return as_value();
- }
-
- SWFMatrix tgtwmat = target->getWorldMatrix();
- SWFMatrix srcwmat = movieclip->getWorldMatrix();
-
- srcwmat.transform(bounds);
- tgtwmat.invert().transform(bounds);
- }
-
- // Magic numbers here... dunno why
- double xMin = 6710886.35;
- double yMin = 6710886.35;
- double xMax = 6710886.35;
- double yMax = 6710886.35;
-
- if ( !bounds.is_null() )
- {
- // Round to the twip
- xMin = twipsToPixels(bounds.get_x_min());
- yMin = twipsToPixels(bounds.get_y_min());
- xMax = twipsToPixels(bounds.get_x_max());
- yMax = twipsToPixels(bounds.get_y_max());
- }
-
- boost::intrusive_ptr<as_object> bounds_obj(new as_object());
- bounds_obj->init_member("xMin", as_value(xMin));
- bounds_obj->init_member("yMin", as_value(yMin));
- bounds_obj->init_member("xMax", as_value(xMax));
- bounds_obj->init_member("yMax", as_value(yMax));
-
- return as_value(bounds_obj.get());
-}
-
-as_value
-movieclip_globalToLocal(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- as_value ret;
-
- if ( fn.nargs < 1 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.globalToLocal() takes one arg"));
- );
- return ret;
- }
-
- boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
- if ( ! obj )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.globalToLocal(%s): "
- "first argument doesn't cast to an object"),
- fn.arg(0));
- );
- return ret;
- }
-
- as_value tmp;
- boost::int32_t x = 0;
- boost::int32_t y = 0;
-
- if ( ! obj->get_member(NSV::PROP_X, &tmp) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.globalToLocal(%s): "
- "object parameter doesn't have an 'x' member"),
- fn.arg(0));
- );
- return ret;
- }
- x = pixelsToTwips(tmp.to_number());
-
- if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.globalToLocal(%s): "
- "object parameter doesn't have an 'y' member"),
- fn.arg(0));
- );
- return ret;
- }
- y = pixelsToTwips(tmp.to_number());
-
- point pt(x, y);
- SWFMatrix world_mat = movieclip->getWorldMatrix();
- world_mat.invert().transform(pt);
-
- obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
- obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
-
- return ret;
-}
-
-as_value
-movieclip_localToGlobal(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- as_value ret;
-
- if ( fn.nargs < 1 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.localToGlobal() takes one arg"));
- );
- return ret;
- }
-
- boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
- if ( ! obj )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.localToGlobal(%s): "
- "first argument doesn't cast to an object"),
- fn.arg(0));
- );
- return ret;
- }
-
- as_value tmp;
- boost::int32_t x = 0;
- boost::int32_t y = 0;
-
- if ( ! obj->get_member(NSV::PROP_X, &tmp) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.localToGlobal(%s): "
- "object parameter doesn't have an 'x' member"),
- fn.arg(0));
- );
- return ret;
- }
- x = pixelsToTwips(tmp.to_number());
-
- if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.localToGlobal(%s): "
- "object parameter doesn't have an 'y' member"),
- fn.arg(0));
- );
- return ret;
- }
- y = pixelsToTwips(tmp.to_number());
-
- point pt(x, y);
- SWFMatrix world_mat = movieclip->getWorldMatrix();
- world_mat.transform(pt);
-
- obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
- obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
- return ret;
-
-}
-
-as_value
-movieclip_setMask(const fn_call& fn)
-{
- // swfdec/test/image/mask-textfield-6.swf shows that setMask should also
- // work against TextFields, we have no tests for other DisplayObject types
so
- // we generalize it for any DisplayObject.
- boost::intrusive_ptr<DisplayObject> maskee =
- ensureType<DisplayObject>(fn.this_ptr);
-
- if ( ! fn.nargs )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("%s.setMask() : needs an argument"),
maskee->getTarget());
- );
- return as_value();
- }
-
- const as_value& arg = fn.arg(0);
- if ( arg.is_null() || arg.is_undefined() )
- {
- // disable mask
- maskee->setMask(NULL);
- }
- else
- {
-
- boost::intrusive_ptr<as_object> obj ( arg.to_object() );
- DisplayObject* mask = dynamic_cast<DisplayObject*>(obj.get());
- if ( ! mask )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("%s.setMask(%s) : first argument is not a
DisplayObject"),
- maskee->getTarget(), arg);
- );
- return as_value();
- }
-
- // ch is possibly NULL, which is intended
- maskee->setMask(mask);
- }
-
- //log_debug("MovieClip.setMask() TESTING");
-
- return as_value(true);
-}
-
-as_value
-movieclip_endFill(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.endFill(%s): args will be discarded"),
- ss.str());
- }
- );
-#ifdef DEBUG_DRAWING_API
- log_debug("%s.endFill();", movieclip->getTarget());
-#endif
- movieclip->endFill();
- return as_value();
-}
-
-as_value
-movieclip_lineTo(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if ( fn.nargs < 2 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.lineTo() needs at least two arguments"));
- );
- return as_value();
- }
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs > 2 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.lineTo(%s): args after the first two "
- "will be discarded"), ss.str());
- }
- );
-
- double x = fn.arg(0).to_number();
- double y = fn.arg(1).to_number();
-
- if (!isFinite(x) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.lineTo(%s) : non-finite first argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(0));
- );
- x = 0;
- }
-
- if (!isFinite(y) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.lineTo(%s) : non-finite second argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(1));
- );
- y = 0;
- }
-
-#ifdef DEBUG_DRAWING_API
- log_debug("%s.lineTo(%g,%g);", movieclip->getTarget(), x, y);
-#endif
- movieclip->lineTo(pixelsToTwips(x), pixelsToTwips(y));
- return as_value();
-}
-
-as_value
-movieclip_moveTo(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if ( fn.nargs < 2 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.moveTo() takes two args"));
- );
- return as_value();
- }
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs > 2 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.moveTo(%s): args after the first two will "
- "be discarded"), ss.str());
- }
- );
-
- double x = fn.arg(0).to_number();
- double y = fn.arg(1).to_number();
-
- if (!isFinite(x) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.moveTo(%s) : non-finite first argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(0));
- );
- x = 0;
- }
-
- if (!isFinite(y) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.moveTo(%s) : non-finite second argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(1));
- );
- y = 0;
- }
-
-#ifdef DEBUG_DRAWING_API
- log_debug(_("%s.moveTo(%g,%g);"), movieclip->getTarget(), x, y);
-#endif
- movieclip->moveTo(pixelsToTwips(x), pixelsToTwips(y));
- return as_value();
-}
-
-// SWF6,7: lineStyle(thickness:Number, rgb:Number, alpha:Number) : Void
-//
-// SWF8+: lineStyle(thickness:Number, rgb:Number, alpha:Number,
-// pixelHinting:Boolean, noScale:String,
-// capsStyle:String, jointStyle:String,
-// miterLimit:Number) : Void
-as_value
-movieclip_lineStyle(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if ( ! fn.nargs )
- {
- movieclip->resetLineStyle();
- return as_value();
- }
-
- boost::uint8_t r = 0;
- boost::uint8_t g = 0;
- boost::uint8_t b = 0;
- boost::uint8_t a = 255;
- boost::uint16_t thickness = 0;
- bool scaleThicknessVertically = true;
- bool scaleThicknessHorizontally = true;
- bool pixelHinting = false;
- bool noClose = false;
- cap_style_e capStyle = CAP_ROUND;
- join_style_e joinStyle = JOIN_ROUND;
- float miterLimitFactor = 1.0f;
-
- int arguments = fn.nargs;
-
- const int swfVersion = movieclip->getVM().getSWFVersion();
- if (swfVersion < 8 && fn.nargs > 3)
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream ss;
- fn.dump_args(ss);
- log_aserror(_("MovieClip.lineStyle(%s): args after the "
- "first three will be discarded"), ss.str());
- );
- arguments = 3;
- }
-
- switch (arguments)
- {
- default:
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream ss;
- fn.dump_args(ss);
- log_aserror(_("MovieClip.lineStyle(%s): args after the "
- "first eight will be discarded"), ss.str());
- );
- case 8:
- miterLimitFactor = clamp<int>(fn.arg(7).to_int(), 1, 255);
- case 7:
- {
- std::string joinStyleStr = fn.arg(6).to_string();
- if (joinStyleStr == "miter") joinStyle = JOIN_MITER;
- else if (joinStyleStr == "round") joinStyle = JOIN_ROUND;
- else if (joinStyleStr == "bevel") joinStyle = JOIN_BEVEL;
- else
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream ss;
- fn.dump_args(ss);
- log_aserror(_("MovieClip.lineStyle(%s): invalid joinStyle"
- "value '%s' (valid values: %s|%s|%s)"),
- ss.str(), joinStyleStr, "miter", "round", "bevel");
- );
- }
- }
- case 6:
- {
- const std::string capStyleStr = fn.arg(5).to_string();
- if (capStyleStr == "none") capStyle = CAP_NONE;
- else if (capStyleStr == "round") capStyle = CAP_ROUND;
- else if (capStyleStr == "square") capStyle = CAP_SQUARE;
- else
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream ss;
- fn.dump_args(ss);
- log_aserror(_("MovieClip.lineStyle(%s): invalid capStyle "
- "value '%s' (valid values: none|round|square)"),
- ss.str(), capStyleStr);
- );
- }
- }
- case 5:
- {
- // Both values to be set here are true, so just set the
- // appropriate values to false.
- const std::string noScaleString = fn.arg(4).to_string();
- if (noScaleString == "none")
- {
- scaleThicknessVertically = false;
- scaleThicknessHorizontally = false;
- }
- else if (noScaleString == "vertical")
- {
- scaleThicknessVertically = false;
- }
- else if (noScaleString == "horizontal")
- {
- scaleThicknessHorizontally = false;
- }
- else if (noScaleString != "normal")
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::ostringstream ss;
- fn.dump_args(ss);
- log_aserror(_("MovieClip.lineStyle(%s): invalid "
- "noScale value '%s' (valid values: "
- "%s|%s|%s|%s)"),
- ss.str(), noScaleString, "none",
- "vertical", "horizontal", "normal");
- );
- }
- }
- case 4:
- pixelHinting = fn.arg(3).to_bool();
- case 3:
- {
- const float alphaval = clamp<float>(fn.arg(2).to_number(),
- 0, 100);
- a = boost::uint8_t(255 * (alphaval / 100));
- }
- case 2:
- {
- // See pollock.swf for eventual regressions.
- // It sets color to a random number from
- // 0 to 160000000 (about 10 times more then the max).
- boost::uint32_t rgbval = fn.arg(1).to_int();
- r = boost::uint8_t((rgbval & 0xFF0000) >> 16);
- g = boost::uint8_t((rgbval & 0x00FF00) >> 8);
- b = boost::uint8_t((rgbval & 0x0000FF) );
- }
- case 1:
- thickness = boost::uint16_t(pixelsToTwips(clamp<float>(
- fn.arg(0).to_number(), 0, 255)));
- break;
- }
-
- rgba color(r, g, b, a);
-
-#ifdef DEBUG_DRAWING_API
- log_debug("%s.lineStyle(%d,%d,%d,%d);", movieclip->getTarget(), thickness,
r, g, b);
-#endif
- movieclip->lineStyle(thickness, color,
- scaleThicknessVertically, scaleThicknessHorizontally,
- pixelHinting, noClose, capStyle, capStyle, joinStyle, miterLimitFactor);
-
- return as_value();
-}
-
-as_value
-movieclip_curveTo(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if ( fn.nargs < 4 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("MovieClip.curveTo() takes four args"));
- );
- return as_value();
- }
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs > 4 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.curveTo(%s): args after the first four "
- "will be discarded"), ss.str());
- }
- );
-
- double cx = fn.arg(0).to_number();
- double cy = fn.arg(1).to_number();
- double ax = fn.arg(2).to_number();
- double ay = fn.arg(3).to_number();
-
- if (!isFinite(cx))
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.curveTo(%s) : non-finite first argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(0));
- );
- cx = 0;
- }
-
- if (!isFinite(cy))
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.curveTo(%s) : non-finite second argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(1));
- );
- cy = 0;
- }
-
- if (!isFinite(ax))
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.curveTo(%s) : non-finite third argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(0));
- );
- ax = 0;
- }
-
- if (!isFinite(ay))
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.curveTo(%s) : non-finite fourth argument (%s), "
- "converted to zero"), movieclip->getTarget(),
- ss.str(), fn.arg(1));
- );
- ay = 0;
- }
-
-#ifdef DEBUG_DRAWING_API
- log_debug(_("%s.curveTo(%g,%g,%g,%g);"), movieclip->getTarget(),
- cx, cy, ax, ay);
-#endif
- movieclip->curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
- pixelsToTwips(ax), pixelsToTwips(ay));
-
- return as_value();
-}
-
-as_value
-movieclip_clear(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.clear(%s): args will be discarded"),
- ss.str());
- }
- );
-
-#ifdef DEBUG_DRAWING_API
- log_debug(_("%s.clear();"), movieclip->getTarget());
-#endif
- movieclip->clear();
-
- return as_value();
-}
-
-as_value
-movieclip_beginFill(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- boost::uint8_t r = 0;
- boost::uint8_t g = 0;
- boost::uint8_t b = 0;
- boost::uint8_t a = 255;
-
- if ( fn.nargs > 0 )
- {
- // 2^24 is the max here
- boost::uint32_t rgbval = boost::uint32_t(
- clamp<float>(fn.arg(0).to_number(), 0, 16777216));
- r = boost::uint8_t( (rgbval&0xFF0000) >> 16);
- g = boost::uint8_t( (rgbval&0x00FF00) >> 8);
- b = boost::uint8_t( (rgbval&0x0000FF) );
-
- if ( fn.nargs > 1 )
- {
- a = 255 * clamp<int>(fn.arg(1).to_int(), 0, 100) / 100;
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs > 2 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.beginFill(%s): args after the "
- "first will be discarded"), ss.str());
- }
- );
- }
-
- }
-
- rgba color(r, g, b, a);
-
-#ifdef DEBUG_DRAWING_API
- log_debug(_("%s.beginFill(%d,%d,%d);"), movieclip->getTarget(), r, g, b);
-#endif
- movieclip->beginFill(color);
-
- return as_value();
-}
-
-as_value
-movieclip_beginGradientFill(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- if ( fn.nargs < 5 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.beginGradientFill(%s): invalid call: 5 arguments "
- "needed"),
- movieclip->getTarget(), ss.str());
- );
- return as_value();
- }
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs > 5 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("MovieClip.beginGradientFill(%s): args after "
- "the first five will be discarded"), ss.str());
- }
- );
-
- bool radial = false;
- std::string typeStr = fn.arg(0).to_string();
- // Case-sensitive comparison needed for this ...
- if ( typeStr == "radial" ) radial = true;
- else if ( typeStr == "linear" ) radial = false;
- else
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.beginGradientFill(%s): first arg must be "
- "'radial' or 'linear'"),
- movieclip->getTarget(), ss.str());
- );
- return as_value();
- }
-
- typedef boost::intrusive_ptr<as_object> ObjPtr;
-
- ObjPtr colors = fn.arg(1).to_object();
- ObjPtr alphas = fn.arg(2).to_object();
- ObjPtr ratios = fn.arg(3).to_object();
- ObjPtr matrixArg = fn.arg(4).to_object();
-
- if ( ! colors || ! alphas || ! ratios || ! matrixArg )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.beginGradientFill(%s): one or more of the "
- " args from 2nd to 5th don't cast to objects"),
- movieclip->getTarget(), ss.str());
- );
- return as_value();
- }
-
- // ----------------------------
- // Parse SWFMatrix
- // ----------------------------
-
- //
- // TODO: fix the SWFMatrix build-up, it is NOT correct for
- // rotation.
- // For the "boxed" SWFMatrixType and radial fills this
- // is not a problem as this code just discards the
- // rotation (which doesn't make sense), but for
- // the explicit SWFMatrix type (a..i) it is a problem.
- // The whole code can likely be simplified by
- // always transforming the gnash gradients to the
- // expected gradients and subsequently applying
- // user-specified SWFMatrix; for 'boxed' SWFMatrixType
- // this simplification would increas cost, but
- // it's too early to apply optimizations to the
- // code (correctness first!!).
- //
-
- SWFMatrix mat;
- SWFMatrix input_matrix;
-
- if ( matrixArg->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box" )
- {
-
- boost::int32_t valX = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_X).to_number());
- boost::int32_t valY = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_Y).to_number());
- boost::int32_t valW = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_W).to_number());
- boost::int32_t valH = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_H).to_number());
- float valR = matrixArg->getMember(NSV::PROP_R).to_number();
-
- if ( radial )
- {
- // Radial gradient is 64x64 twips.
- input_matrix.set_scale(64.0/valW, 64.0/valH);
-
- // For radial gradients, dunno why translation must be negative...
- input_matrix.concatenate_translation( -valX, -valY );
-
- // NOTE: rotation is intentionally discarded as it would
- // have no effect (theoretically origin of the radial
- // fill is at 0,0 making any rotation meaningless).
-
- }
- else
- {
- // Linear gradient is 256x1 twips.
- //
- // No idea why we should use the 256 value for Y scale, but
- // empirically seems to give closer results. Note that it only
- // influences rotation, which is still not correct...
- // TODO: fix it !
- input_matrix.set_scale_rotation(256.0/valW, 256.0/valH, -valR);
-
- // For linear gradients, dunno why translation must be negative...
- input_matrix.concatenate_translation( -valX, -valY );
- }
-
- mat.concatenate(input_matrix);
- }
- else
- {
- float valA = matrixArg->getMember(NSV::PROP_A).to_number() ; // xx
- float valB = matrixArg->getMember(NSV::PROP_B).to_number() ; // yx
- float valD = matrixArg->getMember(NSV::PROP_D).to_number() ; // xy
- float valE = matrixArg->getMember(NSV::PROP_E).to_number() ; // yy
- boost::int32_t valG = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_G).to_number()); // x0
- boost::int32_t valH = pixelsToTwips(
- matrixArg->getMember(NSV::PROP_H).to_number()); // y0
-
- input_matrix.sx = valA * 65536; // sx
- input_matrix.shx = valB * 65536; // shy
- input_matrix.shy = valD * 65536; // shx
- input_matrix.sy = valE * 65536; // sy
- input_matrix.tx = valG; // x0
- input_matrix.ty = valH; // y0
-
- // This is the SWFMatrix that would transform the gnash
- // gradient to the expected flash gradient.
- // Transformation is different for linear and radial
- // gradient for Gnash (in flash they should be the same)
- SWFMatrix gnashToFlash;
-
- if ( radial )
- {
-
- // Gnash radial gradients are 64x64 with center at 32,32
- // Should be 20x20 with center at 0,0
- const double g2fs = 20.0/64.0; // gnash to flash scale
- gnashToFlash.set_scale(g2fs, g2fs);
- gnashToFlash.concatenate_translation(-32, -32);
-
- }
- else
- {
- // First define a SWFMatrix that would transform
- // the gnash gradient to the expected flash gradient:
- // this means translating our gradient to put the
- // center of gradient at 0,0 and then scale it to
- // have a size of 20x20 instead of 256x1 as it is
- //
- // Gnash linear gradients are 256x1 with center at 128,0
- // Should be 20x20 with center at 0,0
- gnashToFlash.set_scale(20.0/256.0, 20.0/1);
- gnashToFlash.concatenate_translation(-128, 0);
-
- }
-
- // Apply gnash to flash SWFMatrix before user-defined one
- input_matrix.concatenate(gnashToFlash);
-
- // Finally, and don't know why, take
- // the inverse of the resulting SWFMatrix as
- // the one which would be used.
- mat = input_matrix;
- mat.invert();
- }
-
- // ----------------------------
- // Create the gradients vector
- // ----------------------------
-
- size_t ngradients = colors->getMember(NSV::PROP_LENGTH).to_int();
- // Check length compatibility of all args
- if ( ngradients != (size_t)alphas->getMember(NSV::PROP_LENGTH).to_int() ||
- ngradients != (size_t)ratios->getMember(NSV::PROP_LENGTH).to_int() )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror(_("%s.beginGradientFill(%s): colors, alphas and "
- "ratios args don't have same length"),
- movieclip->getTarget(), ss.str());
- );
- return as_value();
- }
-
- // TODO: limit ngradients to a max ?
- if ( ngradients > 8 )
- {
- std::stringstream ss; fn.dump_args(ss);
- log_debug(_("%s.beginGradientFill(%s) : too many array elements"
- " for colors and ratios (%d), will trim to 8"),
- movieclip->getTarget(), ss.str(), ngradients);
- ngradients = 8;
- }
-
- VM& vm = movieclip->getVM();
- string_table& st = vm.getStringTable();
-
- std::vector<gradient_record> gradients;
- gradients.reserve(ngradients);
- for (size_t i=0; i<ngradients; ++i)
- {
-
- string_table::key key = st.find(boost::lexical_cast<std::string>(i));
-
- as_value colVal = colors->getMember(key);
- boost::uint32_t col = colVal.is_number() ? colVal.to_int() : 0;
-
- as_value alpVal = alphas->getMember(key);
- boost::uint8_t alp = alpVal.is_number() ?
- clamp<int>(alpVal.to_int(), 0, 255) : 0;
-
- as_value ratVal = ratios->getMember(key);
- boost::uint8_t rat = ratVal.is_number() ?
- clamp<int>(ratVal.to_int(), 0, 255) : 0;
-
- rgba color;
- color.parseRGB(col);
- color.m_a = alp;
-
- gradients.push_back(gradient_record(rat, color));
- }
-
- if ( radial )
- {
- movieclip->beginRadialGradientFill(gradients, mat);
- }
- else
- {
- movieclip->beginLinearGradientFill(gradients, mat);
- }
-
- LOG_ONCE( log_debug("MovieClip.beginGradientFill() TESTING") );
- return as_value();
-}
-
-// startDrag([lockCenter:Boolean], [left:Number], [top:Number],
-// [right:Number], [bottom:Number]) : Void`
-as_value
-movieclip_startDrag(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- drag_state st;
- st.setCharacter( movieclip.get() );
-
- // mark this DisplayObject is transformed.
- movieclip->transformedByScript();
-
- if ( fn.nargs )
- {
- st.setLockCentered( fn.arg(0).to_bool() );
-
- if ( fn.nargs >= 5)
- {
- double x0 = fn.arg(1).to_number();
- double y0 = fn.arg(2).to_number();
- double x1 = fn.arg(3).to_number();
- double y1 = fn.arg(4).to_number();
-
- // check for infinite values
- bool gotinf = false;
- if (!isFinite(x0) ) { x0=0; gotinf=true; }
- if (!isFinite(y0) ) { y0=0; gotinf=true; }
- if (!isFinite(x1) ) { x1=0; gotinf=true; }
- if (!isFinite(y1) ) { y1=0; gotinf=true; }
-
- // check for swapped values
- bool swapped = false;
- if ( y1 < y0 )
- {
- std::swap(y1, y0);
- swapped = true;
- }
-
- if ( x1 < x0 )
- {
- std::swap(x1, x0);
- swapped = true;
- }
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( gotinf || swapped ) {
- std::stringstream ss; fn.dump_args(ss);
- if ( swapped ) {
- log_aserror(_("min/max bbox values in "
- "MovieClip.startDrag(%s) swapped, fixing"),
- ss.str());
- }
- if ( gotinf ) {
- log_aserror(_("non-finite bbox values in "
- "MovieClip.startDrag(%s), took as zero"),
- ss.str());
- }
- }
- );
-
- rect bounds(pixelsToTwips(x0), pixelsToTwips(y0),
- pixelsToTwips(x1), pixelsToTwips(y1));
- st.setBounds(bounds);
- }
- }
-
- movieclip->getVM().getRoot().set_drag_state(st);
-
- return as_value();
-}
-
-// stopDrag() : Void
-as_value
-movieclip_stopDrag(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> movieclip =
- ensureType<MovieClip>(fn.this_ptr);
-
- movieclip->getVM().getRoot().stop_drag();
-
- return as_value();
-}
-
-
-as_value
-movieclip_beginBitmapFill(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(ptr);
- LOG_ONCE( log_unimpl (__FUNCTION__) );
- return as_value();
-}
-
-
-as_value
-movieclip_getRect(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(ptr);
- LOG_ONCE( log_unimpl (__FUNCTION__) );
- return as_value();
-}
-
-
-as_value
-movieclip_lineGradientStyle(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(ptr);
- LOG_ONCE( log_unimpl (__FUNCTION__) );
- return as_value();
-}
-
-
-as_value
-movieclip_attachBitmap(const fn_call& fn)
-{
-
- GNASH_REPORT_FUNCTION;
-
- boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
- if (fn.nargs < 2) {
- IF_VERBOSE_ASCODING_ERRORS(
- log_debug("MovieClip.attachBitmap: expected 2 args, got %d",
- fn.nargs);
- );
- return as_value();
- }
-
- as_object* obj = fn.arg(0).to_object().get();
- boost::intrusive_ptr<BitmapData_as> bd = dynamic_cast<BitmapData_as*>(obj);
-
- if (!bd) {
- IF_VERBOSE_ASCODING_ERRORS(
- log_debug("MovieClip.attachBitmap: first argument should be a "
- "BitmapData", fn.arg(1));
- );
- return as_value();
- }
-
- int depth = fn.arg(1).to_int();
-
- ptr->attachBitmap(bd, depth);
-
- return as_value();
-}
-
-
-as_value
-movieclip_ctor(const fn_call& /* fn */)
-{
- boost::intrusive_ptr<as_object> clip =
- new as_object(getMovieClipInterface());
-
- return as_value(clip.get());
-}
-
-
-as_value
-movieclip_currentframe_get(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(std::min(ptr->get_loaded_frames(),
- ptr->get_current_frame() + 1));
-}
-
-as_value
-movieclip_totalframes_get(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(ptr->get_frame_count());
-}
-
-as_value
-movieclip_framesloaded_get(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(ptr->get_loaded_frames());
-}
-
-as_value
-movieclip_droptarget_getset(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
-
- return ptr->getDropTarget();
-}
-
-as_value
-movieclip_url_getset(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
- return as_value(ptr->get_root()->url());
-}
-
-// TODO: move this to DisplayObject class, _focusrect seems a generic property
-as_value
-movieclip_focusrect_getset(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
- UNUSED(ptr);
-
- if ( fn.nargs == 0 ) // getter
- {
- // Is a yellow rectangle visible around a focused movie clip (?)
- // We don't support focuserct settings
- return as_value(false);
- }
- else // setter
- {
- LOG_ONCE( log_unimpl("MovieClip._focusrect setting") );
- }
- return as_value();
-}
-
-as_value
-movieclip_soundbuftime_getset(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr =
- ensureType<MovieClip>(fn.this_ptr);
- UNUSED(ptr);
-
- if ( fn.nargs == 0 ) // getter
- {
- // Number of seconds before sound starts to stream.
- return as_value(0.0);
- }
- else // setter
- {
- LOG_ONCE( log_unimpl("MovieClip._soundbuftime setting") );
- }
- return as_value();
-}
-
-as_value
-movieclip_transform(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
- // If not found, construction fails.
- as_value transform(fn.env().find_object("flash.geom.Transform"));
-
- boost::intrusive_ptr<as_function> transCtor = transform.to_as_function();
-
- if (!transCtor) {
- log_error("Failed to construct flash.geom.Transform!");
- return as_value();
- }
-
- // Construct a flash.geom.Transform object with "this" as argument.
- std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
- args->push_back(ptr.get());
-
- boost::intrusive_ptr<as_object> newTrans =
- transCtor->constructInstance(fn.env(), args);
-
- return as_value(newTrans.get());
-}
-
-/// Properties (and/or methods) attached to every *instance* of a MovieClip
-void
-attachMovieClipProperties(DisplayObject& o)
-{
- //int target_version = o.getVM().getSWFVersion();
-
- // This is a normal property, can be overridden, deleted and enumerated
- // See swfdec/test/trace/movieclip-version-#.swf for why we only
- // initialize this if we don't have a parent
- if (!o.get_parent()) o.init_member("$version",
- o.getVM().getPlayerVersion(), 0);
-
- as_c_function_ptr gettersetter;
-
- gettersetter = DisplayObject::x_getset;
- o.init_property(NSV::PROP_uX, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::y_getset;
- o.init_property(NSV::PROP_uY, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::xscale_getset;
- o.init_property(NSV::PROP_uXSCALE, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::yscale_getset;
- o.init_property(NSV::PROP_uYSCALE, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::xmouse_get;
- o.init_readonly_property(NSV::PROP_uXMOUSE, gettersetter);
-
- gettersetter = DisplayObject::ymouse_get;
- o.init_readonly_property(NSV::PROP_uYMOUSE, gettersetter);
-
- gettersetter = DisplayObject::alpha_getset;
- o.init_property(NSV::PROP_uALPHA, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::visible_getset;
- o.init_property(NSV::PROP_uVISIBLE, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::width_getset;
- o.init_property(NSV::PROP_uWIDTH, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::height_getset;
- o.init_property(NSV::PROP_uHEIGHT, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::rotation_getset;
- o.init_property(NSV::PROP_uROTATION, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::parent_getset;
- o.init_property(NSV::PROP_uPARENT, gettersetter, gettersetter);
-
- gettersetter = movieclip_currentframe_get;
- o.init_property(NSV::PROP_uCURRENTFRAME, gettersetter, gettersetter);
-
- gettersetter = movieclip_totalframes_get;
- o.init_property(NSV::PROP_uTOTALFRAMES, gettersetter, gettersetter);
-
- gettersetter = movieclip_framesloaded_get;
- o.init_property(NSV::PROP_uFRAMESLOADED, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::target_getset;
- o.init_property(NSV::PROP_uTARGET, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::name_getset;
- o.init_property(NSV::PROP_uNAME, gettersetter, gettersetter);
-
- gettersetter = movieclip_droptarget_getset;
- o.init_property(NSV::PROP_uDROPTARGET, gettersetter, gettersetter);
-
- gettersetter = movieclip_url_getset;
- o.init_property(NSV::PROP_uURL, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::quality;
- o.init_property(NSV::PROP_uQUALITY, gettersetter, gettersetter);
-
- gettersetter = DisplayObject::highquality;
- o.init_property(NSV::PROP_uHIGHQUALITY, gettersetter, gettersetter);
-
- gettersetter = movieclip_focusrect_getset;
- o.init_property(NSV::PROP_uFOCUSRECT, gettersetter, gettersetter);
-
- gettersetter = movieclip_soundbuftime_getset;
- o.init_property(NSV::PROP_uSOUNDBUFTIME, gettersetter, gettersetter);
-
-}
-
-as_object*
-getMovieClipInterface()
-{
- static boost::intrusive_ptr<as_object> proto;
- if ( proto == NULL )
- {
- proto = new as_object(getObjectInterface());
- VM& vm = VM::get();
- vm.addStatic(proto.get());
- registerNatives(vm);
- attachMovieClipInterface(*proto);
- //proto->init_member("constructor", new
builtin_function(movieclip_ctor));
- }
- return proto.get();
-}
-
-} // anonymous namespace
-
-
-
} // namespace gnash
=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h 2009-06-09 07:59:09 +0000
+++ b/libcore/MovieClip.h 2009-06-16 05:42:44 +0000
@@ -988,9 +988,6 @@
bool _lockroot;
};
-/// Initialize the global MovieClip class
-void movieclip_class_init(as_object& global);
-
} // end of namespace gnash
#endif // GNASH_SPRITE_INSTANCE_H
=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp 2009-06-09 15:51:03 +0000
+++ b/libcore/TextField.cpp 2009-06-16 05:42:44 +0000
@@ -2700,8 +2700,7 @@
as_object* obj = 0;
- if ( vm.getSWFVersion() < 9 )
- {
+ if (!isAS3(fn)) {
// We should attach more properties to the prototype on first
// instantiation.
// TODO: this also attaches properties to the SWF5 prototype but makes
@@ -2710,8 +2709,7 @@
obj = new as_object(proto);
}
- else
- {
+ else {
rect nullRect;
obj = new TextField(0, nullRect);
}
=== modified file 'libcore/as_object.cpp'
--- a/libcore/as_object.cpp 2009-06-03 16:05:40 +0000
+++ b/libcore/as_object.cpp 2009-06-16 05:45:41 +0000
@@ -380,8 +380,9 @@
as_object* owner = 0;
string_table& st = vm.getStringTable();
string_table::key k = st.find(fname);
- /*Property* p =*/ findProperty(k, 0, &owner);
- if ( owner != this ) proto = owner; // should be 0 if
findProperty returned 0
+ findProperty(k, 0, &owner);
+ // should be 0 if findProperty returned 0
+ if (owner != this) proto = owner;
}
// proto's __proto__ is superProto
=== modified file 'libcore/asobj/Global.cpp'
--- a/libcore/asobj/Global.cpp 2009-06-12 19:37:55 +0000
+++ b/libcore/asobj/Global.cpp 2009-06-16 05:42:44 +0000
@@ -47,6 +47,7 @@
#include "flash/xml/XMLDocument_as.h"
#include "flash/net/XMLSocket_as.h"
#include "flash/ui/Mouse_as.h"
+#include "flash/display/MovieClip_as.h"
#include "MovieClipLoader.h"
#include "movie_definition.h"
#include "NetConnection_as.h"
@@ -70,7 +71,6 @@
#include "flash_pkg.h"
#include "fn_call.h"
-#include "MovieClip.h"
#include <limits> // for numeric_limits<double>::infinity
#include <sstream>
@@ -111,8 +111,6 @@
as_value global_clearTimeout(const fn_call& fn);
as_value global_clearInterval(const fn_call& fn);
as_value global_setInterval(const fn_call& fn);
- as_value global_addChild(const fn_call& fn);
- as_value global_addChildAt(const fn_call& fn);
void registerNatives(as_object& global);
}
@@ -170,8 +168,6 @@
default:
// Version 10 or above reported
case 9:
- init_member("addChild", new builtin_function(global_addChild));
- init_member("addChildAt", new builtin_function(global_addChildAt));
case 8:
case 7:
@@ -595,114 +591,6 @@
return as_value();
}
-as_value
-global_addChild(const fn_call& fn)
-{
- boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
-
- as_value ret;
-
- if ( ! fn.nargs )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("_global.addChild(): %s", _("missing arguments"));
- );
- return ret;
- }
-
- if ( fn.nargs > 1 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChild(%s): %s", ss.str(), _("ignoring args
after the first"));
- );
- }
-
- as_object* objArg = fn.arg(0).to_object().get();
- if ( ! objArg )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChild(%s): first arg doesn't cast to an
object", ss.str());
- );
- return ret;
- }
-
- DisplayObject* ch = objArg->toDisplayObject();
- if ( ! ch )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChild(%s): first arg doesn't cast to a "
- "DisplayObject", ss.str());
- );
- return ret;
- }
-
- VM& vm = ptr->getVM();
- movie_root& stage = vm.getRoot();
-
- stage.addChild(ch);
-
- return as_value(ch);
-}
-
-as_value
-global_addChildAt(const fn_call& fn)
-{
- boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
-
- as_value ret;
-
- if ( fn.nargs < 2 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("_global.addChildAt(): %s", _("missing arguments"));
- );
- return ret;
- }
-
- if ( fn.nargs > 2 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChildAt(%s): %s", ss.str(), _("ignoring args
after the second"));
- );
- }
-
- as_object* objArg = fn.arg(0).to_object().get();
- if ( ! objArg )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChildAt(%s): first arg doesn't cast to an
object", ss.str());
- );
- return ret;
- }
-
- DisplayObject* ch = objArg->toDisplayObject();
- if ( ! ch )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("_global.addChildAt(%s): first arg doesn't cast to a "
- "DisplayObject", ss.str());
- );
- return ret;
- }
-
- int depth = fn.arg(1).to_number();
-
- VM& vm = ptr->getVM();
- movie_root& stage = vm.getRoot();
-
- std::stringstream ss; fn.dump_args(ss);
- log_debug("TESTING: _global.addChildAt(%s)", ss.str());
-
- stage.addChildAt(ch, depth);
-
- return as_value(ch);
-}
as_value
global_setInterval(const fn_call& fn)
@@ -885,6 +773,7 @@
vm.registerNative(global_setInterval, 250, 0);
vm.registerNative(global_clearInterval, 250, 1);
+ registerMovieClipNative(global);
registerSelectionNative(global);
registerColorNative(global);
registerMathNative(global);
=== modified file 'libcore/asobj/flash/display/DisplayObjectContainer_as.cpp'
--- a/libcore/asobj/flash/display/DisplayObjectContainer_as.cpp 2009-05-28
17:10:05 +0000
+++ b/libcore/asobj/flash/display/DisplayObjectContainer_as.cpp 2009-06-04
11:51:18 +0000
@@ -1,4 +1,4 @@
-// DisplayObjectContainer_as.cpp: ActionScript "DisplayObjectContainer"
class, for Gnash.
+// DisplayObjectContainer_as.cpp: ActionScript "DisplayObjectContainer" class.
//
// Copyright (C) 2009 Free Software Foundation, Inc.
//
@@ -21,19 +21,21 @@
#include "gnashconfig.h"
#endif
+#include "DisplayObjectContainer.h"
#include "display/DisplayObjectContainer_as.h"
#include "log.h"
#include "fn_call.h"
-#include "smart_ptr.h" // for boost intrusive_ptr
-#include "builtin_function.h" // need builtin_function
-#include "GnashException.h" // for ActionException
+#include "smart_ptr.h"
+#include "builtin_function.h"
namespace gnash {
// Forward declarations
namespace {
as_value displayobjectcontainer_addChildAt(const fn_call& fn);
- as_value displayobjectcontainer_areInaccessibleObjectsUnderPoint(const
fn_call& fn);
+ as_value displayobjectcontainer_addChild(const fn_call& fn);
+ as_value displayobjectcontainer_areInaccessibleObjectsUnderPoint(
+ const fn_call& fn);
as_value displayobjectcontainer_contains(const fn_call& fn);
as_value displayobjectcontainer_getChildAt(const fn_call& fn);
as_value displayobjectcontainer_getChildByName(const fn_call& fn);
@@ -44,61 +46,28 @@
as_value displayobjectcontainer_setChildIndex(const fn_call& fn);
as_value displayobjectcontainer_swapChildren(const fn_call& fn);
as_value displayobjectcontainer_swapChildrenAt(const fn_call& fn);
+ as_value displayobjectcontainer_numChildren(const fn_call& fn);
as_value displayobjectcontainer_ctor(const fn_call& fn);
void attachDisplayObjectContainerInterface(as_object& o);
- void attachDisplayObjectContainerStaticInterface(as_object& o);
- as_object* getDisplayObjectContainerInterface();
-
}
-class DisplayObjectContainer_as : public as_object
-{
-
-public:
-
- DisplayObjectContainer_as()
- :
- as_object(getDisplayObjectContainerInterface())
- {}
-};
-
// extern (used by Global.cpp)
-void displayobjectcontainer_class_init(as_object& global)
+void
+displayobjectcontainer_class_init(as_object& where)
{
+
+ // This should never be called during AVM1 execution!
+ assert(isAS3(where.getVM()));
+
static boost::intrusive_ptr<builtin_function> cl;
if (!cl) {
- cl = new builtin_function(&displayobjectcontainer_ctor,
getDisplayObjectContainerInterface());
- attachDisplayObjectContainerStaticInterface(*cl);
+ cl = new builtin_function(&displayobjectcontainer_ctor,
+ getDisplayObjectContainerInterface());
}
// Register _global.DisplayObjectContainer
- global.init_member("DisplayObjectContainer", cl.get());
-}
-
-namespace {
-
-void
-attachDisplayObjectContainerInterface(as_object& o)
-{
- o.init_member("addChildAt", new
builtin_function(displayobjectcontainer_addChildAt));
- o.init_member("areInaccessibleObjectsUnderPoint", new
builtin_function(displayobjectcontainer_areInaccessibleObjectsUnderPoint));
- o.init_member("contains", new
builtin_function(displayobjectcontainer_contains));
- o.init_member("getChildAt", new
builtin_function(displayobjectcontainer_getChildAt));
- o.init_member("getChildByName", new
builtin_function(displayobjectcontainer_getChildByName));
- o.init_member("getChildIndex", new
builtin_function(displayobjectcontainer_getChildIndex));
- o.init_member("getObjectsUnderPoint", new
builtin_function(displayobjectcontainer_getObjectsUnderPoint));
- o.init_member("removeChild", new
builtin_function(displayobjectcontainer_removeChild));
- o.init_member("removeChildAt", new
builtin_function(displayobjectcontainer_removeChildAt));
- o.init_member("setChildIndex", new
builtin_function(displayobjectcontainer_setChildIndex));
- o.init_member("swapChildren", new
builtin_function(displayobjectcontainer_swapChildren));
- o.init_member("swapChildrenAt", new
builtin_function(displayobjectcontainer_swapChildrenAt));
-}
-
-void
-attachDisplayObjectContainerStaticInterface(as_object& o)
-{
-
+ where.init_member("DisplayObjectContainer", cl.get());
}
as_object*
@@ -112,21 +81,145 @@
return o.get();
}
+namespace {
+
+void
+attachDisplayObjectContainerInterface(as_object& o)
+{
+ o.init_member("addChildAt", new builtin_function(
+ displayobjectcontainer_addChildAt));
+ o.init_member("addChild", new builtin_function(
+ displayobjectcontainer_addChild));
+ o.init_member("areInaccessibleObjectsUnderPoint", new builtin_function(
+ displayobjectcontainer_areInaccessibleObjectsUnderPoint));
+ o.init_member("contains", new builtin_function(
+ displayobjectcontainer_contains));
+ o.init_member("getChildAt", new builtin_function(
+ displayobjectcontainer_getChildAt));
+ o.init_member("getChildByName", new builtin_function(
+ displayobjectcontainer_getChildByName));
+ o.init_member("getChildIndex", new builtin_function(
+ displayobjectcontainer_getChildIndex));
+ o.init_member("getObjectsUnderPoint", new builtin_function(
+ displayobjectcontainer_getObjectsUnderPoint));
+ o.init_member("removeChild", new builtin_function(
+ displayobjectcontainer_removeChild));
+ o.init_member("removeChildAt", new builtin_function(
+ displayobjectcontainer_removeChildAt));
+ o.init_member("setChildIndex", new builtin_function(
+ displayobjectcontainer_setChildIndex));
+ o.init_member("swapChildren", new builtin_function(
+ displayobjectcontainer_swapChildren));
+ o.init_member("swapChildrenAt", new builtin_function(
+ displayobjectcontainer_swapChildrenAt));
+ o.init_readonly_property("numChildren",
+ displayobjectcontainer_numChildren);
+}
+
+
+as_value
+displayobjectcontainer_addChild(const fn_call& fn)
+{
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
+
+ as_value ret;
+
+ if (!fn.nargs) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("addChild(): %s", _("missing arguments"));
+ );
+ return ret;
+ }
+
+ if (fn.nargs > 1) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChild(%s): %s", ss.str(), _("ignoring args after "
+ "the first"));
+ );
+ }
+
+ as_object* objArg = fn.arg(0).to_object().get();
+ if (!objArg) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChild(%s): first arg doesn't cast to an object",
+ ss.str());
+ );
+ return ret;
+ }
+
+ DisplayObject* ch = objArg->toDisplayObject();
+ if (!ch) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChild(%s): first arg doesn't cast to a "
+ "DisplayObject", ss.str());
+ );
+ return ret;
+ }
+
+ return as_value(ptr->addChild(ch));
+}
+
as_value
displayobjectcontainer_addChildAt(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
+
+ as_value ret;
+
+ if (fn.nargs < 2) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("addChildAt(): %s", _("missing arguments"));
+ );
+ return ret;
+ }
+
+ if (fn.nargs > 2) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChildAt(%s): %s", ss.str(), _("ignoring args after "
+ "the second"));
+ );
+ }
+
+ as_object* objArg = fn.arg(0).to_object().get();
+ if (!objArg) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChildAt(%s): first arg doesn't cast to an object",
+ ss.str());
+ );
+ return ret;
+ }
+
+ DisplayObject* ch = objArg->toDisplayObject();
+ if (!ch) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("addChildAt(%s): first arg doesn't cast to a "
+ "DisplayObject", ss.str());
+ );
+ return ret;
+ }
+
+ int depth = fn.arg(1).to_number();
+
+ std::stringstream ss; fn.dump_args(ss);
+ log_debug("TESTING: addChildAt(%s)", ss.str());
+
+ return as_value(ptr->addChildAt(ch, depth));
+
}
as_value
displayobjectcontainer_areInaccessibleObjectsUnderPoint(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -135,8 +228,8 @@
as_value
displayobjectcontainer_contains(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -145,8 +238,8 @@
as_value
displayobjectcontainer_getChildAt(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -155,18 +248,26 @@
as_value
displayobjectcontainer_getChildByName(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
}
as_value
+displayobjectcontainer_numChildren(const fn_call& fn)
+{
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
+ return as_value(ptr->numChildren());
+}
+
+as_value
displayobjectcontainer_getChildIndex(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -175,8 +276,8 @@
as_value
displayobjectcontainer_getObjectsUnderPoint(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -185,8 +286,8 @@
as_value
displayobjectcontainer_removeChild(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -195,8 +296,8 @@
as_value
displayobjectcontainer_removeChildAt(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -205,8 +306,8 @@
as_value
displayobjectcontainer_setChildIndex(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -215,8 +316,8 @@
as_value
displayobjectcontainer_swapChildren(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -225,8 +326,8 @@
as_value
displayobjectcontainer_swapChildrenAt(const fn_call& fn)
{
- boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
- ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+ boost::intrusive_ptr<DisplayObjectContainer> ptr =
+ ensureType<DisplayObjectContainer>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -235,9 +336,12 @@
as_value
displayobjectcontainer_ctor(const fn_call& fn)
{
- boost::intrusive_ptr<as_object> obj = new DisplayObjectContainer_as;
+ // This should never be called during AS2 execution!
+ assert(isAS3(fn));
- return as_value(obj.get()); // will keep alive
+ log_unimpl("Attempt to construct a DisplayObjectContainer should throw"
+ "an exception!");
+ return as_value();
}
} // anonymous namespace
=== modified file 'libcore/asobj/flash/display/DisplayObjectContainer_as.h'
--- a/libcore/asobj/flash/display/DisplayObjectContainer_as.h 2009-05-28
17:29:17 +0000
+++ b/libcore/asobj/flash/display/DisplayObjectContainer_as.h 2009-06-04
05:33:47 +0000
@@ -33,6 +33,9 @@
/// Initialize the global DisplayObjectContainer class
void displayobjectcontainer_class_init(as_object& global);
+/// Get an as_object with the DisplayObjectContainer interface.
+as_object* getDisplayObjectContainerInterface();
+
} // gnash namespace
// GNASH_ASOBJ3_DISPLAYOBJECTCONTAINER_H
=== modified file 'libcore/asobj/flash/display/MovieClip_as.cpp'
--- a/libcore/asobj/flash/display/MovieClip_as.cpp 2009-05-28 17:10:05
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.cpp 2009-06-16 06:52:04
+0000
@@ -21,60 +21,2628 @@
#include "gnashconfig.h"
#endif
+#include "MovieClip.h"
+#include "Movie.h"
#include "display/MovieClip_as.h"
+#include "display/DisplayObjectContainer_as.h"
+#include "display/BitmapData_as.h"
+#include "NetStream_as.h"
+#include "movie_root.h"
+#include "GnashNumeric.h"
+#include "as_value.h"
+#include "Object.h"
#include "log.h"
#include "fn_call.h"
#include "smart_ptr.h" // for boost intrusive_ptr
#include "builtin_function.h" // need builtin_function
-#include "GnashException.h" // for ActionException
namespace gnash {
// Forward declarations
namespace {
+
+ void attachMovieClipAS2Interface(as_object& o);
+
+ as_value movieclip_as2_ctor(const fn_call& fn);
+ as_value movieclip_transform(const fn_call& fn);
+ as_value movieclip_scale9Grid(const fn_call& fn);
+ as_value movieclip_attachVideo(const fn_call& fn);
+ as_value movieclip_attachAudio(const fn_call& fn);
+ as_value movieclip_attachMovie(const fn_call& fn);
+ as_value movieclip_unloadMovie(const fn_call& fn);
+ as_value movieclip_loadMovie(const fn_call& fn);
+ as_value movieclip_getURL(const fn_call& fn);
+ as_value movieclip_attachBitmap(const fn_call& fn);
+ as_value movieclip_beginBitmapFill(const fn_call& fn);
+ as_value movieclip_createEmptyMovieClip(const fn_call& fn);
+ as_value movieclip_removeMovieClip(const fn_call& fn);
+ as_value movieclip_createTextField(const fn_call& fn);
+ as_value movieclip_curveTo(const fn_call& fn);
+ as_value movieclip_beginFill(const fn_call& fn);
+ as_value movieclip_prevFrame(const fn_call& fn);
+ as_value movieclip_nextFrame(const fn_call& fn);
+ as_value movieclip_endFill(const fn_call& fn);
+ as_value movieclip_clear(const fn_call& fn);
+ as_value movieclip_lineStyle(const fn_call& fn);
+ as_value movieclip_lineTo(const fn_call& fn);
+ as_value movieclip_moveTo(const fn_call& fn);
+ as_value movieclip_beginGradientFill(const fn_call& fn);
+ as_value movieclip_stopDrag(const fn_call& fn);
+ as_value movieclip_startDrag(const fn_call& fn);
+ as_value movieclip_removeMovieClip(const fn_call& fn);
as_value movieclip_gotoAndStop(const fn_call& fn);
- as_value movieclip_nextFrame(const fn_call& fn);
+ as_value movieclip_duplicateMovieClip(const fn_call& fn);
+ as_value movieclip_gotoAndPlay(const fn_call& fn);
+ as_value movieclip_stop(const fn_call& fn);
+ as_value movieclip_play(const fn_call& fn);
+ as_value movieclip_setMask(const fn_call& fn);
+ as_value movieclip_getDepth(const fn_call& fn);
+ as_value movieclip_getBytesTotal(const fn_call& fn);
+ as_value movieclip_getBytesLoaded(const fn_call& fn);
+ as_value movieclip_getBounds(const fn_call& fn);
+ as_value movieclip_hitTest(const fn_call& fn);
+ as_value movieclip_globalToLocal(const fn_call& fn);
+ as_value movieclip_localToGlobal(const fn_call& fn);
+ as_value movieclip_swapDepths(const fn_call& fn);
+ as_value movieclip_scrollRect(const fn_call& fn);
+ as_value movieclip_getInstanceAtDepth(const fn_call& fn);
+ as_value movieclip_getNextHighestDepth(const fn_call& fn);
+ as_value movieclip_getTextSnapshot(const fn_call& fn);
+ as_value movieclip_tabIndex(const fn_call& fn);
+ as_value movieclip_opaqueBackground(const fn_call& fn);
+ as_value movieclip_filters(const fn_call& fn);
+ as_value movieclip_forceSmoothing(const fn_call& fn);
+ as_value movieclip_cacheAsBitmap(const fn_call& fn);
+ as_value movieclip_lineGradientStyle(const fn_call& fn);
+ as_value movieclip_getRect(const fn_call& fn);
+ as_value movieclip_meth(const fn_call& fn);
+ as_value movieclip_getSWFVersion(const fn_call& fn);
+ as_value movieclip_loadVariables(const fn_call& fn);
+ as_value movieclip_currentFrame(const fn_call& fn);
+ as_value movieclip_totalFrames(const fn_call& fn);
+ as_value movieclip_framesLoaded(const fn_call& fn);
+ as_value movieclip_dropTarget(const fn_call& fn);
+ as_value movieclip_url(const fn_call& fn);
+ as_value movieclip_focusRect(const fn_call& fn);
+ as_value movieclip_soundbuftime(const fn_call& fn);
+
+ // =============================================
+ // AS3 methods
+ // =============================================
+
+ void attachMovieClipAS3Interface(as_object& o);
+ as_value movieclip_as3_ctor(const fn_call& fn);
as_value movieclip_nextScene(const fn_call& fn);
- as_value movieclip_play(const fn_call& fn);
- as_value movieclip_prevFrame(const fn_call& fn);
as_value movieclip_prevScene(const fn_call& fn);
- as_value movieclip_stop(const fn_call& fn);
- as_value movieclip_ctor(const fn_call& fn);
- void attachMovieClipInterface(as_object& o);
- void attachMovieClipStaticInterface(as_object& o);
- as_object* getMovieClipInterface();
}
-class MovieClip_as : public as_object
-{
-
-public:
-
- MovieClip_as()
- :
- as_object(getMovieClipInterface())
- {}
-};
-
// extern (used by Global.cpp)
-void movieclip_class_init(as_object& global)
+void
+movieclip_class_init(as_object& where)
{
+ if (isAS3(where.getVM())) {
+
+ static boost::intrusive_ptr<builtin_function> cl;
+
+ if (!cl) {
+ cl = new builtin_function(&movieclip_as3_ctor,
+ getMovieClipAS3Interface());
+
+ where.getVM().addStatic(cl.get());
+ }
+
+ log_debug("AVM2 MovieClip, ctor %s", cl.get());
+
+ where.init_member("MovieClip", cl.get());
+ return;
+ }
+
static boost::intrusive_ptr<builtin_function> cl;
if (!cl) {
- cl = new builtin_function(&movieclip_ctor, getMovieClipInterface());
- attachMovieClipStaticInterface(*cl);
- }
-
- // Register _global.MovieClip
- global.init_member("MovieClip", cl.get());
-}
+ cl = new builtin_function(&movieclip_as2_ctor,
+ getMovieClipAS2Interface());
+
+ where.getVM().addStatic(cl.get());
+ }
+
+ where.init_member("MovieClip", cl.get());
+}
+
+as_object*
+getMovieClipAS3Interface()
+{
+ static boost::intrusive_ptr<as_object> o;
+ if ( ! o ) {
+ o = getDisplayObjectContainerInterface();
+ attachMovieClipAS3Interface(*o);
+ }
+ return o.get();
+}
+
+void
+registerMovieClipNative(as_object& global)
+{
+ VM& vm = global.getVM();
+
+ // Natives are always here (at least in swf5 I guess)
+ vm.registerNative(movieclip_attachMovie, 900, 0);
+ // TODO: generalize to DisplayObject::swapDepths_method ?
+ vm.registerNative(movieclip_swapDepths, 900, 1);
+ vm.registerNative(movieclip_localToGlobal, 900, 2);
+ vm.registerNative(movieclip_globalToLocal, 900, 3);
+ vm.registerNative(movieclip_hitTest, 900, 4);
+ vm.registerNative(movieclip_getBounds, 900, 5);
+ vm.registerNative(movieclip_getBytesTotal, 900, 6);
+ vm.registerNative(movieclip_getBytesLoaded, 900, 7);
+ vm.registerNative(movieclip_attachAudio, 900, 8);
+ vm.registerNative(movieclip_attachVideo, 900, 9);
+ // TODO: generalize to DisplayObject::getDepth_method ?
+ vm.registerNative(movieclip_getDepth, 900, 10);
+ vm.registerNative(movieclip_setMask, 900, 11);
+ vm.registerNative(movieclip_play, 900, 12);
+ vm.registerNative(movieclip_stop, 900, 13);
+ vm.registerNative(movieclip_nextFrame, 900, 14);
+ vm.registerNative(movieclip_prevFrame, 900, 15);
+ vm.registerNative(movieclip_gotoAndPlay, 900, 16);
+ vm.registerNative(movieclip_gotoAndStop, 900, 17);
+ vm.registerNative(movieclip_duplicateMovieClip, 900, 18);
+ vm.registerNative(movieclip_removeMovieClip, 900, 19);
+ vm.registerNative(movieclip_startDrag, 900, 20);
+ vm.registerNative(movieclip_stopDrag, 900, 21);
+ vm.registerNative(movieclip_createEmptyMovieClip, 901, 0);
+ vm.registerNative(movieclip_beginFill, 901, 1);
+ vm.registerNative(movieclip_beginGradientFill, 901, 2);
+ vm.registerNative(movieclip_moveTo, 901, 3);
+ vm.registerNative(movieclip_lineTo, 901, 4);
+ vm.registerNative(movieclip_curveTo, 901, 5);
+ vm.registerNative(movieclip_lineStyle, 901, 6);
+ vm.registerNative(movieclip_endFill, 901, 7);
+ vm.registerNative(movieclip_clear, 901, 8);
+
+ vm.registerNative(movieclip_createTextField, 104, 200);
+
+}
+
+/// Properties (and/or methods) attached to every *instance* of a MovieClip
+void
+attachMovieClipAS2Properties(DisplayObject& o)
+{
+
+ // This is a normal property, can be overridden, deleted and enumerated
+ // See swfdec/test/trace/movieclip-version-#.swf for why we only
+ // initialize this if we don't have a parent
+ if (!o.get_parent()) o.init_member("$version",
+ o.getVM().getPlayerVersion(), 0);
+
+ as_c_function_ptr gettersetter;
+
+ gettersetter = DisplayObject::x_getset;
+ o.init_property(NSV::PROP_uX, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::y_getset;
+ o.init_property(NSV::PROP_uY, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::xscale_getset;
+ o.init_property(NSV::PROP_uXSCALE, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::yscale_getset;
+ o.init_property(NSV::PROP_uYSCALE, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::xmouse_get;
+ o.init_readonly_property(NSV::PROP_uXMOUSE, gettersetter);
+
+ gettersetter = DisplayObject::ymouse_get;
+ o.init_readonly_property(NSV::PROP_uYMOUSE, gettersetter);
+
+ gettersetter = DisplayObject::alpha_getset;
+ o.init_property(NSV::PROP_uALPHA, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::visible_getset;
+ o.init_property(NSV::PROP_uVISIBLE, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::width_getset;
+ o.init_property(NSV::PROP_uWIDTH, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::height_getset;
+ o.init_property(NSV::PROP_uHEIGHT, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::rotation_getset;
+ o.init_property(NSV::PROP_uROTATION, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::parent_getset;
+ o.init_property(NSV::PROP_uPARENT, gettersetter, gettersetter);
+
+ gettersetter = movieclip_currentFrame;
+ o.init_property(NSV::PROP_uCURRENTFRAME, gettersetter, gettersetter);
+
+ gettersetter = movieclip_totalFrames;
+ o.init_property(NSV::PROP_uTOTALFRAMES, gettersetter, gettersetter);
+
+ gettersetter = movieclip_framesLoaded;
+ o.init_property(NSV::PROP_uFRAMESLOADED, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::target_getset;
+ o.init_property(NSV::PROP_uTARGET, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::name_getset;
+ o.init_property(NSV::PROP_uNAME, gettersetter, gettersetter);
+
+ gettersetter = movieclip_dropTarget;
+ o.init_property(NSV::PROP_uDROPTARGET, gettersetter, gettersetter);
+
+ gettersetter = movieclip_url;
+ o.init_property(NSV::PROP_uURL, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::quality;
+ o.init_property(NSV::PROP_uQUALITY, gettersetter, gettersetter);
+
+ gettersetter = DisplayObject::highquality;
+ o.init_property(NSV::PROP_uHIGHQUALITY, gettersetter, gettersetter);
+
+ gettersetter = movieclip_focusRect;
+ o.init_property(NSV::PROP_uFOCUSRECT, gettersetter, gettersetter);
+
+ gettersetter = movieclip_soundbuftime;
+ o.init_property(NSV::PROP_uSOUNDBUFTIME, gettersetter, gettersetter);
+
+}
+
+as_object*
+getMovieClipAS2Interface()
+{
+ static boost::intrusive_ptr<as_object> proto;
+ if ( proto == NULL )
+ {
+ proto = new as_object(getObjectInterface());
+ VM& vm = VM::get();
+ vm.addStatic(proto.get());
+ attachMovieClipAS2Interface(*proto);
+ }
+ return proto.get();
+}
+
namespace {
-void
-attachMovieClipInterface(as_object& o)
+// =======================
+// AS2 interface
+// =======================
+
+/// Properties (and/or methods) *inherited* by MovieClip instances
+void
+attachMovieClipAS2Interface(as_object& o)
+{
+ VM& vm = o.getVM();
+
+ o.init_member("attachMovie", vm.getNative(900, 0));
+ o.init_member("swapDepths", vm.getNative(900, 1));
+ o.init_member("localToGlobal", vm.getNative(900, 2));
+ o.init_member("globalToLocal", vm.getNative(900, 3));
+ o.init_member("hitTest", vm.getNative(900, 4));
+ o.init_member("getBounds", vm.getNative(900, 5));
+ o.init_member("getBytesTotal", vm.getNative(900, 6));
+ o.init_member("getBytesLoaded", vm.getNative(900, 7));
+ o.init_member("play", vm.getNative(900, 12));
+ o.init_member("stop", vm.getNative(900, 13));
+ o.init_member("nextFrame", vm.getNative(900, 14));
+ o.init_member("prevFrame", vm.getNative(900, 15));
+ o.init_member("gotoAndPlay", vm.getNative(900, 16));
+ o.init_member("gotoAndStop", vm.getNative(900, 17));
+ o.init_member("duplicateMovieClip", vm.getNative(900, 18));
+ o.init_member("removeMovieClip", vm.getNative(900, 19));
+ o.init_member("startDrag", vm.getNative(900, 20));
+ o.init_member("stopDrag", vm.getNative(900, 21));
+ o.init_member("loadMovie", new builtin_function(movieclip_loadMovie));
+ o.init_member("loadVariables", new builtin_function(
+ movieclip_loadVariables));
+ o.init_member("unloadMovie", new builtin_function(
+ movieclip_unloadMovie));
+ o.init_member("getURL", new builtin_function(movieclip_getURL));
+ o.init_member("getSWFVersion", new builtin_function(
+ movieclip_getSWFVersion));
+ o.init_member("meth", new builtin_function(movieclip_meth));
+ o.init_member("enabled", true);
+ o.init_member("useHandCursor", true);
+ o.init_property("_lockroot", &MovieClip::lockroot_getset,
+ &MovieClip::lockroot_getset);
+ o.init_member("beginBitmapFill", new builtin_function(
+ movieclip_beginBitmapFill));
+ o.init_member("getRect", new builtin_function(
+ movieclip_getRect));
+ o.init_member("lineGradientStyle", new builtin_function(
+ movieclip_lineGradientStyle));
+ o.init_member("attachBitmap", new builtin_function(
+ movieclip_attachBitmap));
+ o.init_property("blendMode", &DisplayObject::blendMode,
+ &DisplayObject::blendMode);
+ o.init_property("cacheAsBitmap", &movieclip_cacheAsBitmap,
+ &movieclip_cacheAsBitmap);
+ o.init_property("filters", &movieclip_filters, &movieclip_filters);
+ o.init_property("forceSmoothing", &movieclip_forceSmoothing,
+ &movieclip_forceSmoothing);
+ o.init_property("opaqueBackground", &movieclip_opaqueBackground,
+ &movieclip_opaqueBackground);
+ o.init_property("scale9Grid", &movieclip_scale9Grid,
+ movieclip_scale9Grid);
+ o.init_property("scrollRect", &movieclip_scrollRect,
+ &movieclip_scrollRect);
+ o.init_property("tabIndex", &movieclip_tabIndex, &movieclip_tabIndex);
+ o.init_property("transform", &movieclip_transform,
+ &movieclip_transform);
+
+ const int swf6Flags = as_prop_flags::dontDelete |
+ as_prop_flags::dontEnum |
+ as_prop_flags::onlySWF6Up;
+
+ o.init_member("attachAudio", vm.getNative(900, 8), swf6Flags);
+ o.init_member("attachVideo", vm.getNative(900, 9), swf6Flags);
+ o.init_member("getDepth", vm.getNative(900, 10), swf6Flags);
+ o.init_member("setMask", vm.getNative(900, 11), swf6Flags);
+ o.init_member("createEmptyMovieClip", vm.getNative(901, 0), swf6Flags);
+ o.init_member("beginFill", vm.getNative(901, 1), swf6Flags);
+ o.init_member("beginGradientFill", vm.getNative(901, 2), swf6Flags);
+ o.init_member("moveTo", vm.getNative(901, 3), swf6Flags);
+ o.init_member("lineTo", vm.getNative(901, 4), swf6Flags);
+ o.init_member("curveTo", vm.getNative(901, 5), swf6Flags);
+ o.init_member("lineStyle", vm.getNative(901, 6), swf6Flags);
+ o.init_member("endFill", vm.getNative(901, 7), swf6Flags);
+ o.init_member("clear", vm.getNative(901, 8), swf6Flags);
+ o.init_member("createTextField", vm.getNative(104, 200), swf6Flags);
+ o.init_member("getTextSnapshot",
+ new builtin_function(movieclip_getTextSnapshot), swf6Flags);
+
+ const int swf7Flags = as_prop_flags::dontDelete |
+ as_prop_flags::dontEnum |
+ as_prop_flags::onlySWF7Up;
+
+ o.init_member("getNextHighestDepth", new builtin_function(
+ movieclip_getNextHighestDepth), swf7Flags);
+ o.init_member("getInstanceAtDepth", new builtin_function(
+ movieclip_getInstanceAtDepth), swf7Flags);
+
+}
+
+
+as_value
+movieclip_play(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
+ return as_value();
+}
+
+as_value
+movieclip_stop(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+
+ return as_value();
+}
+
+
+//removeMovieClip() : Void
+as_value
+movieclip_removeMovieClip(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ movieclip->removeMovieClip();
+ return as_value();
+}
+
+
+as_value
+movieclip_cacheAsBitmap(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE( log_unimpl(_("MovieClip.cacheAsBitmap()")) );
+ return as_value();
+}
+
+
+as_value
+movieclip_filters(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.filters()")));
+ return as_value();
+}
+
+
+as_value
+movieclip_forceSmoothing(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.forceSmoothing()")));
+ return as_value();
+}
+
+
+as_value
+movieclip_opaqueBackground(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.opaqueBackground()")));
+ return as_value();
+}
+
+
+as_value
+movieclip_scale9Grid(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.scale9Grid()")));
+ return as_value();
+}
+
+
+as_value
+movieclip_scrollRect(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.scrollRect()")));
+ return as_value();
+}
+
+
+as_value
+movieclip_tabIndex(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+ LOG_ONCE(log_unimpl(_("MovieClip.tabIndex()")));
+ return as_value();
+}
+
+
+// attachMovie(idName:String, newName:String,
+// depth:Number [, initObject:Object]) : MovieClip
+as_value
+movieclip_attachMovie(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 3 || fn.nargs > 4)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("attachMovie called with wrong number of arguments"
+ " expected 3 to 4, got (%d) - returning undefined"), fn.nargs);
+ );
+ return as_value();
+ }
+
+ // Get exported resource
+ const std::string& id_name = fn.arg(0).to_string();
+
+ boost::intrusive_ptr<ExportableResource> exported =
+ movieclip->get_root()->definition()->get_exported_resource(id_name);
+
+ if (!exported)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("attachMovie: '%s': no such exported resource - "
+ "returning undefined"), id_name);
+ );
+ return as_value();
+ }
+
+ SWF::DefinitionTag* exported_movie =
+ dynamic_cast<SWF::DefinitionTag*>(exported.get());
+
+ if (!exported_movie)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("attachMovie: exported resource '%s' "
+ "is not a DisplayObject definition (%s) -- "
+ "returning undefined"), id_name,
+ typeid(*(exported.get())).name());
+ );
+ return as_value();
+ }
+
+ const std::string& newname = fn.arg(1).to_string();
+
+ // Movies should be attachable from -16384 to 2130690045, according to
+ // kirupa (http://www.kirupa.com/developer/actionscript/depths2.htm)
+ // Tests in misc-ming.all/DepthLimitsTest.c show that 2130690044 is the
+ // maximum valid depth.
+ const double depth = fn.arg(2).to_number();
+
+ // This also checks for overflow, as both numbers are expressible as
+ // boost::int32_t.
+ if (depth < DisplayObject::lowerAccessibleBound ||
+ depth > DisplayObject::upperAccessibleBound)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.attachMovie: invalid depth %d "
+ "passed; not attaching"), depth);
+ );
+ return as_value();
+ }
+
+ boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
+
+ boost::intrusive_ptr<DisplayObject> newch =
+ exported_movie->createDisplayObject(movieclip.get(), 0);
+
+#ifndef GNASH_USE_GC
+ assert(newch->get_ref_count() > 0);
+#endif // ndef GNASH_USE_GC
+
+ newch->set_name(newname);
+ newch->setDynamic();
+
+ boost::intrusive_ptr<as_object> initObj;
+
+ if (fn.nargs > 3 ) {
+ initObj = fn.arg(3).to_object();
+ if (!initObj) {
+ // This is actually a valid thing to do,
+ // the documented behaviour is to just NOT
+ // initialize the properties in this
+ // case.
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Fourth argument of attachMovie doesn't cast to "
+ "an object (%s), we'll act as if it wasn't given"),
+ fn.arg(3));
+ );
+ }
+ }
+
+ // placeDisplayObject() will set depth on newch
+ if (!movieclip->attachCharacter(*newch, depthValue, initObj.get()))
+ {
+ log_error(_("Could not attach DisplayObject at depth %d"), depthValue);
+ return as_value();
+ }
+
+ return as_value(newch.get());
+}
+
+
+// attachAudio(id:Object) : Void
+as_value
+movieclip_attachAudio(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (!fn.nargs)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("MovieClip.attachAudio(): %s", _("missing arguments"));
+ );
+ return as_value();
+ }
+
+ as_object* obj = fn.arg(0).to_object().get();
+ if ( ! obj )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ // TODO: find out what to do here
+ log_error("MovieClip.attachAudio(%s): first arg doesn't cast to "
+ "an object", ss.str());
+ return as_value();
+ }
+
+ NetStream_as* ns = dynamic_cast<NetStream_as*>(obj);
+ if ( ! ns )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ // TODO: find out what to do here
+ log_error("MovieClip.attachAudio(%s): first arg doesn't cast to a "
+ "NetStream", ss.str());
+ return as_value();
+ }
+
+ ns->setAudioController(movieclip.get());
+
+ LOG_ONCE( log_unimpl("MovieClip.attachAudio() - TESTING") );
+ return as_value();
+}
+
+
+// MovieClip.attachVideo
+as_value
+movieclip_attachVideo(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(movieclip);
+
+ LOG_ONCE( log_unimpl("MovieClip.attachVideo()") );
+ return as_value();
+}
+
+
+//createEmptyMovieClip(name:String, depth:Number) : MovieClip
+as_value
+movieclip_createEmptyMovieClip(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs != 2)
+ {
+ if (fn.nargs < 2)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("createEmptyMovieClip needs "
+ "2 args, but %d given,"
+ " returning undefined"),
+ fn.nargs);
+ );
+ return as_value();
+ }
+ else
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("createEmptyMovieClip takes "
+ "2 args, but %d given, discarding"
+ " the excess"),
+ fn.nargs);
+ )
+ }
+ }
+
+ // Unlike other MovieClip methods, the depth argument of an empty movie
clip
+ // can be any number. All numbers are converted to an int32_t, and are
valid
+ // depths even when outside the usual bounds.
+ DisplayObject* ch = movieclip->add_empty_movieclip(fn.arg(0).to_string(),
+ fn.arg(1).to_int());
+ return as_value(ch);
+}
+
+as_value
+movieclip_getDepth(const fn_call& fn)
+{
+ // TODO: make this a DisplayObject::getDepth_method function...
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ const int n = movieclip->get_depth();
+
+ return as_value(n);
+}
+
+//swapDepths(target:Object|target:Number)
+//
+// Returns void.
+as_value
+movieclip_swapDepths(const fn_call& fn)
+{
+
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ const int this_depth = movieclip->get_depth();
+
+ if (fn.nargs < 1)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("%s.swapDepths() needs one arg"),
movieclip->getTarget());
+ );
+ return as_value();
+ }
+
+ // Lower bound of source depth below which swapDepth has no effect
+ // (below Timeline/static zone)
+ if ( this_depth < DisplayObject::lowerAccessibleBound )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("%s.swapDepths(%s): won't swap a clip below "
+ "depth %d (%d)"),
+ movieclip->getTarget(), ss.str(),
DisplayObject::lowerAccessibleBound,
+ this_depth);
+ );
+ return as_value();
+ }
+
+ typedef boost::intrusive_ptr<DisplayObject> CharPtr;
+ typedef boost::intrusive_ptr<MovieClip> SpritePtr;
+
+ SpritePtr this_parent = dynamic_cast<MovieClip*>(
+ movieclip->get_parent());
+
+ //CharPtr target = NULL;
+ int target_depth = 0;
+
+ // movieclip.swapDepth(movieclip)
+ if ( SpritePtr target_movieclip = fn.arg(0).to_sprite() )
+ {
+ if ( movieclip == target_movieclip )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("%s.swapDepths(%s): invalid call, swapping to
self?"),
+ movieclip->getTarget(), target_movieclip->getTarget());
+ );
+ return as_value();
+ }
+
+ SpritePtr target_parent =
+ dynamic_cast<MovieClip*>(movieclip->get_parent());
+ if ( this_parent != target_parent )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("%s.swapDepths(%s): invalid call, the two "
+ "DisplayObjects don't have the same parent"),
+ movieclip->getTarget(), target_movieclip->getTarget());
+ );
+ return as_value();
+ }
+
+ target_depth = target_movieclip->get_depth();
+
+ // Check we're not swapping the our own depth so
+ // to avoid unecessary bounds invalidation and immunizing
+ // the instance from subsequent PlaceObject tags attempting
+ // to transform it.
+ if ( movieclip->get_depth() == target_depth )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.swapDepths(%s): ignored, source and "
+ "target DisplayObjects have the same depth %d"),
+ movieclip->getTarget(), ss.str(), target_depth);
+ );
+ return as_value();
+ }
+ }
+
+ // movieclip.swapDepth(depth)
+ else
+ {
+ double td = fn.arg(0).to_number();
+ if ( isNaN(td) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.swapDepths(%s): first argument invalid "
+ "(neither a movieclip nor a number)"),
+ movieclip->getTarget(), ss.str());
+ );
+ return as_value();
+ }
+
+ target_depth = int(td);
+
+ // Check we're not swapping the our own depth so
+ // to avoid unecessary bounds invalidation and immunizing
+ // the instance from subsequent PlaceObjec tags attempting
+ // to transform it.
+ if ( movieclip->get_depth() == target_depth )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.swapDepths(%s): ignored, DisplayObject already "
+ "at depth %d"),
+ movieclip->getTarget(), ss.str(), target_depth);
+ );
+ return as_value();
+ }
+
+
+ // TODO : check other kind of validities ?
+
+
+ }
+
+ if ( this_parent )
+ {
+ this_parent->swapDepths(movieclip.get(), target_depth);
+ }
+ else
+ {
+ movie_root& root = movieclip->getVM().getRoot();
+ root.swapLevels(movieclip, target_depth);
+ return as_value();
+ }
+
+ return as_value();
+
+}
+
+// TODO: wrap the functionality in a MovieClip method
+// and invoke it from here, this should only be a wrapper
+//
+//duplicateMovieClip(name:String, depth:Number, [initObject:Object]) :
MovieClip
+as_value
+movieclip_duplicateMovieClip(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 2)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.duplicateMovieClip() needs 2 or 3 args"));
+ );
+ return as_value();
+ }
+
+ const std::string& newname = fn.arg(0).to_string();
+
+ // Depth as in attachMovie
+ const double depth = fn.arg(1).to_number();
+
+ // This also checks for overflow, as both numbers are expressible as
+ // boost::int32_t.
+ if (depth < DisplayObject::lowerAccessibleBound ||
+ depth > DisplayObject::upperAccessibleBound)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.duplicateMovieClip: "
+ "invalid depth %d passed; not duplicating"), depth);
+ );
+ return as_value();
+ }
+
+ boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
+
+ boost::intrusive_ptr<MovieClip> ch;
+
+ // Copy members from initObject
+ if (fn.nargs == 3)
+ {
+ boost::intrusive_ptr<as_object> initObject = fn.arg(2).to_object();
+ ch = movieclip->duplicateMovieClip(newname, depthValue,
+ initObject.get());
+ }
+ else
+ {
+ ch = movieclip->duplicateMovieClip(newname, depthValue);
+ }
+
+ return as_value(ch.get());
+}
+
+as_value
+movieclip_gotoAndPlay(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 1)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("movieclip_goto_and_play needs one arg"));
+ );
+ return as_value();
+ }
+
+ size_t frame_number;
+ if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
+ {
+ // No dice.
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("movieclip_goto_and_play('%s') -- invalid frame"),
+ fn.arg(0));
+ );
+ return as_value();
+ }
+
+ // Convert to 0-based
+ movieclip->goto_frame(frame_number);
+ movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
+ return as_value();
+}
+
+as_value movieclip_gotoAndStop(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 1)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("movieclip_goto_and_stop needs one arg"));
+ );
+ return as_value();
+ }
+
+ size_t frame_number;
+ if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
+ {
+ // No dice.
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("movieclip_goto_and_stop('%s') -- invalid frame"),
+ fn.arg(0));
+ );
+ return as_value();
+ }
+
+ // Convert to 0-based
+ movieclip->goto_frame(frame_number);
+ movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+ return as_value();
+}
+
+as_value movieclip_nextFrame(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ const size_t frame_count = movieclip->get_frame_count();
+ const size_t current_frame = movieclip->get_current_frame();
+ if (current_frame < frame_count)
+ {
+ movieclip->goto_frame(current_frame + 1);
+ }
+ movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+ return as_value();
+}
+
+as_value
+movieclip_prevFrame(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ const size_t current_frame = movieclip->get_current_frame();
+ if (current_frame > 0)
+ {
+ movieclip->goto_frame(current_frame - 1);
+ }
+ movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+ return as_value();
+}
+
+as_value
+movieclip_getBytesLoaded(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(movieclip->get_bytes_loaded());
+}
+
+as_value
+movieclip_getBytesTotal(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ // @@ horrible uh ?
+ return as_value(movieclip->get_bytes_total());
+}
+
+// MovieClip.loadMovie(url:String [,variables:String]).
+//
+// Returns 1 for "get", 2 for "post", and otherwise 0. Case-insensitive.
+// This *always* calls MovieClip.meth.
+as_value
+movieclip_loadMovie(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ as_value val;
+ if (fn.nargs > 1) {
+ val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
+ }
+ else val = movieclip->callMethod(NSV::PROP_METH);
+
+ if (fn.nargs < 1) // url
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.loadMovie() "
+ "expected 1 or 2 args, got %d - returning undefined"),
+ fn.nargs);
+ );
+ return as_value();
+ }
+
+ const std::string& urlstr = fn.arg(0).to_string();
+ if (urlstr.empty())
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("First argument of MovieClip.loadMovie(%s) "
+ "evaluates to an empty string - "
+ "returning undefined"),
+ ss.str());
+ );
+ return as_value();
+ }
+
+ movie_root& mr = movieclip->getVM().getRoot();
+ std::string target = movieclip->getTarget();
+
+ // TODO: if GET/POST should send variables of *this* movie,
+ // no matter if the target will be replaced by another movie !!
+ const MovieClip::VariablesMethod method =
+ static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+ std::string data;
+
+ // This is just an optimization if we aren't going
+ // to send the data anyway. It might be wrong, though.
+ if (method != MovieClip::METHOD_NONE)
+ {
+ movieclip->getURLEncodedVars(data);
+ }
+
+ mr.loadMovie(urlstr, target, data, method);
+
+ return as_value();
+}
+
+// my_mc.loadVariables(url:String [, variables:String]) : Void
+as_value
+movieclip_loadVariables(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ // This always calls MovieClip.meth, even when there are no
+ // arguments.
+ as_value val;
+ if (fn.nargs > 1)
+ {
+ val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
+ }
+ else val = movieclip->callMethod(NSV::PROP_METH);
+
+ if (fn.nargs < 1) // url
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.loadVariables() "
+ "expected 1 or 2 args, got %d - returning undefined"),
+ fn.nargs);
+ );
+ return as_value();
+ }
+
+ const std::string& urlstr = fn.arg(0).to_string();
+ if (urlstr.empty())
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("First argument passed to MovieClip.loadVariables(%s) "
+ "evaluates to an empty string - "
+ "returning undefined"),
+ ss.str());
+ );
+ return as_value();
+ }
+
+ const MovieClip::VariablesMethod method =
+ static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+ movieclip->loadVariables(urlstr, method);
+ log_debug("MovieClip.loadVariables(%s) - TESTING ", urlstr);
+
+ return as_value();
+}
+
+// my_mc.unloadMovie() : Void
+as_value
+movieclip_unloadMovie(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ movieclip->unloadMovie();
+
+ return as_value();
+}
+
+as_value
+movieclip_hitTest(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ switch (fn.nargs)
+ {
+ case 1: // target
+ {
+ const as_value& tgt_val = fn.arg(0);
+ DisplayObject* target = fn.env().find_target(tgt_val.to_string());
+ if ( ! target )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Can't find hitTest target %s"),
+ tgt_val);
+ );
+ return as_value();
+ }
+
+ rect thisbounds = movieclip->getBounds();
+ SWFMatrix thismat = movieclip->getWorldMatrix();
+ thismat.transform(thisbounds);
+
+ rect tgtbounds = target->getBounds();
+ SWFMatrix tgtmat = target->getWorldMatrix();
+ tgtmat.transform(tgtbounds);
+
+ return thisbounds.getRange().intersects(tgtbounds.getRange());
+
+ break;
+ }
+
+ case 2: // x, y
+ {
+ boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
+ boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
+
+ return movieclip->pointInBounds(x, y);
+ }
+
+ case 3: // x, y, shapeFlag
+ {
+ boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
+ boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
+ bool shapeFlag = fn.arg(2).to_bool();
+
+ if ( ! shapeFlag ) return movieclip->pointInBounds(x, y);
+ else return movieclip->pointInHitableShape(x, y);
+ }
+
+ default:
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("hitTest() called with %u args"),
+ fn.nargs);
+ );
+ break;
+ }
+ }
+
+ return as_value();
+
+}
+
+as_value
+movieclip_createTextField(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 6) // name, depth, x, y, width, height
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("createTextField called with %d args, "
+ "expected 6 - returning undefined"), fn.nargs);
+ );
+ return as_value();
+ }
+
+ std::string txt_name = fn.arg(0).to_string();
+
+ int txt_depth = fn.arg(1).to_int();
+
+ int txt_x = fn.arg(2).to_int();
+
+ int txt_y = fn.arg(3).to_int();
+
+ int txt_width = fn.arg(4).to_int();
+ if ( txt_width < 0 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("createTextField: negative width (%d)"
+ " - reverting sign"), txt_width);
+ );
+ txt_width = -txt_width;
+ }
+
+ int txt_height = fn.arg(5).to_int();
+ if ( txt_height < 0 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("createTextField: negative height (%d)"
+ " - reverting sign"), txt_height);
+ );
+ txt_height = -txt_height;
+ }
+
+ boost::intrusive_ptr<DisplayObject> txt =
movieclip->add_textfield(txt_name,
+ txt_depth, txt_x, txt_y, txt_width, txt_height);
+
+ // createTextField returns void, it seems
+ if ( movieclip->getVM().getSWFVersion() > 7 ) return as_value(txt.get());
+ else return as_value();
+}
+
+//getNextHighestDepth() : Number
+as_value
+movieclip_getNextHighestDepth(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ int nextdepth = movieclip->getNextHighestDepth();
+ return as_value(static_cast<double>(nextdepth));
+}
+
+//getInstanceAtDepth(depth:Number) : MovieClip
+as_value
+movieclip_getInstanceAtDepth(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> mc = ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 1)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("MovieClip.getInstanceAtDepth(): missing depth argument");
+ );
+ return as_value();
+ }
+
+ int depth = fn.arg(0).to_int();
+ boost::intrusive_ptr<DisplayObject> ch =
mc->getDisplayObjectAtDepth(depth);
+
+ // we want 'undefined', not 'null'
+ if (!ch) return as_value();
+ return as_value(ch.get());
+}
+
+/// MovieClip.getURL(url:String[, window:String[, method:String]])
+//
+/// Tested manually to function as a method of any as_object. Hard to
+/// test automatically as it doesn't return anything and only has external
+/// side-effects.
+/// Returns void.
+as_value
+movieclip_getURL(const fn_call& fn)
+{
+ boost::intrusive_ptr<as_object> movieclip =
+ ensureType<as_object>(fn.this_ptr);
+
+ std::string urlstr;
+ std::string target;
+
+ as_value val;
+ if (fn.nargs > 2)
+ {
+ val = movieclip->callMethod(NSV::PROP_METH, fn.arg(2));
+ }
+ else val = movieclip->callMethod(NSV::PROP_METH);
+
+ switch (fn.nargs)
+ {
+ case 0:
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("No arguments passed to MovieClip.getURL()"));
+ );
+ return as_value();
+ }
+ default:
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream os;
+ fn.dump_args(os);
+ log_aserror(_("MovieClip.getURL(%s): extra arguments "
+ "dropped"), os.str());
+ );
+ }
+ case 3:
+ // This argument has already been handled.
+ case 2:
+ target = fn.arg(1).to_string();
+ case 1:
+ urlstr = fn.arg(0).to_string();
+ break;
+ }
+
+
+ MovieClip::VariablesMethod method =
+ static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+ std::string vars;
+
+ if (method != MovieClip::METHOD_NONE) {
+ // Get encoded vars.
+ movieclip->getURLEncodedVars(vars);
+ }
+
+ movie_root& m = movieclip->getVM().getRoot();
+
+ m.getURL(urlstr, target, vars, method);
+
+ return as_value();
+}
+
+// getSWFVersion() : Number
+as_value
+movieclip_getSWFVersion(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(movieclip->getSWFVersion());
+}
+
+// MovieClip.meth(<string>) : Number
+//
+// Parses case-insensitive "get" and "post" into 1 and 2, 0 anything else
+//
+as_value
+movieclip_meth(const fn_call& fn)
+{
+
+ if (!fn.nargs) return as_value(MovieClip::METHOD_NONE);
+
+ const as_value& v = fn.arg(0);
+ boost::intrusive_ptr<as_object> o = v.to_object();
+ if ( ! o )
+ {
+ log_debug(_("meth(%s): first argument doesn't cast to object"), v);
+ return as_value(MovieClip::METHOD_NONE);
+ }
+
+ as_value lc = o->callMethod(NSV::PROP_TO_LOWER_CASE);
+
+ std::string s = lc.to_string();
+
+ if (s == "get") return as_value(MovieClip::METHOD_GET);
+ if (s == "post") return as_value(MovieClip::METHOD_POST);
+ return as_value(MovieClip::METHOD_NONE);
+}
+
+
+// getTextSnapshot() : TextSnapshot
+as_value
+movieclip_getTextSnapshot(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> obj = ensureType<MovieClip>(fn.this_ptr);
+
+ // If not found, construction fails.
+ as_value textSnapshot(fn.env().find_object("TextSnapshot"));
+
+ boost::intrusive_ptr<as_function> tsCtor = textSnapshot.to_as_function();
+
+ if (!tsCtor) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("MovieClip.getTextSnapshot: failed to construct "
+ "TextSnapshot (object probably overridden)");
+ );
+ return as_value();
+ }
+
+ // Construct a flash.geom.Transform object with "this" as argument.
+ std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+ args->push_back(obj.get());
+
+ boost::intrusive_ptr<as_object> ts =
+ tsCtor->constructInstance(fn.env(), args);
+
+ return as_value(ts.get());
+}
+
+
+// getBounds(targetCoordinateSpace:Object) : Object
+as_value
+movieclip_getBounds(const fn_call& fn)
+{
+ boost::intrusive_ptr<DisplayObject> movieclip =
+ ensureType<DisplayObject>(fn.this_ptr);
+
+ rect bounds = movieclip->getBounds();
+
+ if ( fn.nargs > 0 )
+ {
+ DisplayObject* target = fn.arg(0).toDisplayObject();
+ if ( ! target )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.getBounds(%s): invalid call, first "
+ "arg must be a DisplayObject"),
+ fn.arg(0));
+ );
+ return as_value();
+ }
+
+ SWFMatrix tgtwmat = target->getWorldMatrix();
+ SWFMatrix srcwmat = movieclip->getWorldMatrix();
+
+ srcwmat.transform(bounds);
+ tgtwmat.invert().transform(bounds);
+ }
+
+ // Magic numbers here... dunno why
+ double xMin = 6710886.35;
+ double yMin = 6710886.35;
+ double xMax = 6710886.35;
+ double yMax = 6710886.35;
+
+ if ( !bounds.is_null() )
+ {
+ // Round to the twip
+ xMin = twipsToPixels(bounds.get_x_min());
+ yMin = twipsToPixels(bounds.get_y_min());
+ xMax = twipsToPixels(bounds.get_x_max());
+ yMax = twipsToPixels(bounds.get_y_max());
+ }
+
+ boost::intrusive_ptr<as_object> bounds_obj(new as_object());
+ bounds_obj->init_member("xMin", as_value(xMin));
+ bounds_obj->init_member("yMin", as_value(yMin));
+ bounds_obj->init_member("xMax", as_value(xMax));
+ bounds_obj->init_member("yMax", as_value(yMax));
+
+ return as_value(bounds_obj.get());
+}
+
+as_value
+movieclip_globalToLocal(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ as_value ret;
+
+ if ( fn.nargs < 1 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.globalToLocal() takes one arg"));
+ );
+ return ret;
+ }
+
+ boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
+ if ( ! obj )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.globalToLocal(%s): "
+ "first argument doesn't cast to an object"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+
+ as_value tmp;
+ boost::int32_t x = 0;
+ boost::int32_t y = 0;
+
+ if ( ! obj->get_member(NSV::PROP_X, &tmp) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.globalToLocal(%s): "
+ "object parameter doesn't have an 'x' member"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+ x = pixelsToTwips(tmp.to_number());
+
+ if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.globalToLocal(%s): "
+ "object parameter doesn't have an 'y' member"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+ y = pixelsToTwips(tmp.to_number());
+
+ point pt(x, y);
+ SWFMatrix world_mat = movieclip->getWorldMatrix();
+ world_mat.invert().transform(pt);
+
+ obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
+ obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
+
+ return ret;
+}
+
+as_value
+movieclip_localToGlobal(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ as_value ret;
+
+ if ( fn.nargs < 1 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.localToGlobal() takes one arg"));
+ );
+ return ret;
+ }
+
+ boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
+ if ( ! obj )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.localToGlobal(%s): "
+ "first argument doesn't cast to an object"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+
+ as_value tmp;
+ boost::int32_t x = 0;
+ boost::int32_t y = 0;
+
+ if ( ! obj->get_member(NSV::PROP_X, &tmp) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.localToGlobal(%s): "
+ "object parameter doesn't have an 'x' member"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+ x = pixelsToTwips(tmp.to_number());
+
+ if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.localToGlobal(%s): "
+ "object parameter doesn't have an 'y' member"),
+ fn.arg(0));
+ );
+ return ret;
+ }
+ y = pixelsToTwips(tmp.to_number());
+
+ point pt(x, y);
+ SWFMatrix world_mat = movieclip->getWorldMatrix();
+ world_mat.transform(pt);
+
+ obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
+ obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
+ return ret;
+
+}
+
+as_value
+movieclip_setMask(const fn_call& fn)
+{
+ // swfdec/test/image/mask-textfield-6.swf shows that setMask should also
+ // work against TextFields, we have no tests for other DisplayObject types
so
+ // we generalize it for any DisplayObject.
+ boost::intrusive_ptr<DisplayObject> maskee =
+ ensureType<DisplayObject>(fn.this_ptr);
+
+ if ( ! fn.nargs )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("%s.setMask() : needs an argument"),
maskee->getTarget());
+ );
+ return as_value();
+ }
+
+ const as_value& arg = fn.arg(0);
+ if ( arg.is_null() || arg.is_undefined() )
+ {
+ // disable mask
+ maskee->setMask(NULL);
+ }
+ else
+ {
+
+ boost::intrusive_ptr<as_object> obj ( arg.to_object() );
+ DisplayObject* mask = dynamic_cast<DisplayObject*>(obj.get());
+ if ( ! mask )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("%s.setMask(%s) : first argument is not a
DisplayObject"),
+ maskee->getTarget(), arg);
+ );
+ return as_value();
+ }
+
+ // ch is possibly NULL, which is intended
+ maskee->setMask(mask);
+ }
+
+ //log_debug("MovieClip.setMask() TESTING");
+
+ return as_value(true);
+}
+
+as_value
+movieclip_endFill(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.endFill(%s): args will be discarded"),
+ ss.str());
+ }
+ );
+#ifdef DEBUG_DRAWING_API
+ log_debug("%s.endFill();", movieclip->getTarget());
+#endif
+ movieclip->endFill();
+ return as_value();
+}
+
+as_value
+movieclip_lineTo(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if ( fn.nargs < 2 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.lineTo() needs at least two arguments"));
+ );
+ return as_value();
+ }
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs > 2 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineTo(%s): args after the first two "
+ "will be discarded"), ss.str());
+ }
+ );
+
+ double x = fn.arg(0).to_number();
+ double y = fn.arg(1).to_number();
+
+ if (!isFinite(x) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.lineTo(%s) : non-finite first argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(0));
+ );
+ x = 0;
+ }
+
+ if (!isFinite(y) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.lineTo(%s) : non-finite second argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(1));
+ );
+ y = 0;
+ }
+
+#ifdef DEBUG_DRAWING_API
+ log_debug("%s.lineTo(%g,%g);", movieclip->getTarget(), x, y);
+#endif
+ movieclip->lineTo(pixelsToTwips(x), pixelsToTwips(y));
+ return as_value();
+}
+
+as_value
+movieclip_moveTo(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if ( fn.nargs < 2 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.moveTo() takes two args"));
+ );
+ return as_value();
+ }
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs > 2 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.moveTo(%s): args after the first two will "
+ "be discarded"), ss.str());
+ }
+ );
+
+ double x = fn.arg(0).to_number();
+ double y = fn.arg(1).to_number();
+
+ if (!isFinite(x) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.moveTo(%s) : non-finite first argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(0));
+ );
+ x = 0;
+ }
+
+ if (!isFinite(y) )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.moveTo(%s) : non-finite second argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(1));
+ );
+ y = 0;
+ }
+
+#ifdef DEBUG_DRAWING_API
+ log_debug(_("%s.moveTo(%g,%g);"), movieclip->getTarget(), x, y);
+#endif
+ movieclip->moveTo(pixelsToTwips(x), pixelsToTwips(y));
+ return as_value();
+}
+
+// SWF6,7: lineStyle(thickness:Number, rgb:Number, alpha:Number) : Void
+//
+// SWF8+: lineStyle(thickness:Number, rgb:Number, alpha:Number,
+// pixelHinting:Boolean, noScale:String,
+// capsStyle:String, jointStyle:String,
+// miterLimit:Number) : Void
+as_value
+movieclip_lineStyle(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if ( ! fn.nargs )
+ {
+ movieclip->resetLineStyle();
+ return as_value();
+ }
+
+ boost::uint8_t r = 0;
+ boost::uint8_t g = 0;
+ boost::uint8_t b = 0;
+ boost::uint8_t a = 255;
+ boost::uint16_t thickness = 0;
+ bool scaleThicknessVertically = true;
+ bool scaleThicknessHorizontally = true;
+ bool pixelHinting = false;
+ bool noClose = false;
+ cap_style_e capStyle = CAP_ROUND;
+ join_style_e joinStyle = JOIN_ROUND;
+ float miterLimitFactor = 1.0f;
+
+ int arguments = fn.nargs;
+
+ const int swfVersion = movieclip->getVM().getSWFVersion();
+ if (swfVersion < 8 && fn.nargs > 3)
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineStyle(%s): args after the "
+ "first three will be discarded"), ss.str());
+ );
+ arguments = 3;
+ }
+
+ switch (arguments)
+ {
+ default:
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineStyle(%s): args after the "
+ "first eight will be discarded"), ss.str());
+ );
+ case 8:
+ miterLimitFactor = clamp<int>(fn.arg(7).to_int(), 1, 255);
+ case 7:
+ {
+ std::string joinStyleStr = fn.arg(6).to_string();
+ if (joinStyleStr == "miter") joinStyle = JOIN_MITER;
+ else if (joinStyleStr == "round") joinStyle = JOIN_ROUND;
+ else if (joinStyleStr == "bevel") joinStyle = JOIN_BEVEL;
+ else
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineStyle(%s): invalid joinStyle"
+ "value '%s' (valid values: %s|%s|%s)"),
+ ss.str(), joinStyleStr, "miter", "round", "bevel");
+ );
+ }
+ }
+ case 6:
+ {
+ const std::string capStyleStr = fn.arg(5).to_string();
+ if (capStyleStr == "none") capStyle = CAP_NONE;
+ else if (capStyleStr == "round") capStyle = CAP_ROUND;
+ else if (capStyleStr == "square") capStyle = CAP_SQUARE;
+ else
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineStyle(%s): invalid capStyle "
+ "value '%s' (valid values: none|round|square)"),
+ ss.str(), capStyleStr);
+ );
+ }
+ }
+ case 5:
+ {
+ // Both values to be set here are true, so just set the
+ // appropriate values to false.
+ const std::string noScaleString = fn.arg(4).to_string();
+ if (noScaleString == "none")
+ {
+ scaleThicknessVertically = false;
+ scaleThicknessHorizontally = false;
+ }
+ else if (noScaleString == "vertical")
+ {
+ scaleThicknessVertically = false;
+ }
+ else if (noScaleString == "horizontal")
+ {
+ scaleThicknessHorizontally = false;
+ }
+ else if (noScaleString != "normal")
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("MovieClip.lineStyle(%s): invalid "
+ "noScale value '%s' (valid values: "
+ "%s|%s|%s|%s)"),
+ ss.str(), noScaleString, "none",
+ "vertical", "horizontal", "normal");
+ );
+ }
+ }
+ case 4:
+ pixelHinting = fn.arg(3).to_bool();
+ case 3:
+ {
+ const float alphaval = clamp<float>(fn.arg(2).to_number(),
+ 0, 100);
+ a = boost::uint8_t(255 * (alphaval / 100));
+ }
+ case 2:
+ {
+ // See pollock.swf for eventual regressions.
+ // It sets color to a random number from
+ // 0 to 160000000 (about 10 times more then the max).
+ boost::uint32_t rgbval = fn.arg(1).to_int();
+ r = boost::uint8_t((rgbval & 0xFF0000) >> 16);
+ g = boost::uint8_t((rgbval & 0x00FF00) >> 8);
+ b = boost::uint8_t((rgbval & 0x0000FF) );
+ }
+ case 1:
+ thickness = boost::uint16_t(pixelsToTwips(clamp<float>(
+ fn.arg(0).to_number(), 0, 255)));
+ break;
+ }
+
+ rgba color(r, g, b, a);
+
+#ifdef DEBUG_DRAWING_API
+ log_debug("%s.lineStyle(%d,%d,%d,%d);", movieclip->getTarget(), thickness,
r, g, b);
+#endif
+ movieclip->lineStyle(thickness, color,
+ scaleThicknessVertically, scaleThicknessHorizontally,
+ pixelHinting, noClose, capStyle, capStyle, joinStyle, miterLimitFactor);
+
+ return as_value();
+}
+
+as_value
+movieclip_curveTo(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if ( fn.nargs < 4 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("MovieClip.curveTo() takes four args"));
+ );
+ return as_value();
+ }
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs > 4 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.curveTo(%s): args after the first four "
+ "will be discarded"), ss.str());
+ }
+ );
+
+ double cx = fn.arg(0).to_number();
+ double cy = fn.arg(1).to_number();
+ double ax = fn.arg(2).to_number();
+ double ay = fn.arg(3).to_number();
+
+ if (!isFinite(cx))
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.curveTo(%s) : non-finite first argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(0));
+ );
+ cx = 0;
+ }
+
+ if (!isFinite(cy))
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.curveTo(%s) : non-finite second argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(1));
+ );
+ cy = 0;
+ }
+
+ if (!isFinite(ax))
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.curveTo(%s) : non-finite third argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(0));
+ );
+ ax = 0;
+ }
+
+ if (!isFinite(ay))
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.curveTo(%s) : non-finite fourth argument (%s), "
+ "converted to zero"), movieclip->getTarget(),
+ ss.str(), fn.arg(1));
+ );
+ ay = 0;
+ }
+
+#ifdef DEBUG_DRAWING_API
+ log_debug(_("%s.curveTo(%g,%g,%g,%g);"), movieclip->getTarget(),
+ cx, cy, ax, ay);
+#endif
+ movieclip->curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
+ pixelsToTwips(ax), pixelsToTwips(ay));
+
+ return as_value();
+}
+
+as_value
+movieclip_clear(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.clear(%s): args will be discarded"),
+ ss.str());
+ }
+ );
+
+#ifdef DEBUG_DRAWING_API
+ log_debug(_("%s.clear();"), movieclip->getTarget());
+#endif
+ movieclip->clear();
+
+ return as_value();
+}
+
+as_value
+movieclip_beginFill(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ boost::uint8_t r = 0;
+ boost::uint8_t g = 0;
+ boost::uint8_t b = 0;
+ boost::uint8_t a = 255;
+
+ if ( fn.nargs > 0 )
+ {
+ // 2^24 is the max here
+ boost::uint32_t rgbval = boost::uint32_t(
+ clamp<float>(fn.arg(0).to_number(), 0, 16777216));
+ r = boost::uint8_t( (rgbval&0xFF0000) >> 16);
+ g = boost::uint8_t( (rgbval&0x00FF00) >> 8);
+ b = boost::uint8_t( (rgbval&0x0000FF) );
+
+ if ( fn.nargs > 1 )
+ {
+ a = 255 * clamp<int>(fn.arg(1).to_int(), 0, 100) / 100;
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs > 2 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.beginFill(%s): args after the "
+ "first will be discarded"), ss.str());
+ }
+ );
+ }
+
+ }
+
+ rgba color(r, g, b, a);
+
+#ifdef DEBUG_DRAWING_API
+ log_debug(_("%s.beginFill(%d,%d,%d);"), movieclip->getTarget(), r, g, b);
+#endif
+ movieclip->beginFill(color);
+
+ return as_value();
+}
+
+as_value
+movieclip_beginGradientFill(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ if ( fn.nargs < 5 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.beginGradientFill(%s): invalid call: 5 arguments "
+ "needed"),
+ movieclip->getTarget(), ss.str());
+ );
+ return as_value();
+ }
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs > 5 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("MovieClip.beginGradientFill(%s): args after "
+ "the first five will be discarded"), ss.str());
+ }
+ );
+
+ bool radial = false;
+ std::string typeStr = fn.arg(0).to_string();
+ // Case-sensitive comparison needed for this ...
+ if ( typeStr == "radial" ) radial = true;
+ else if ( typeStr == "linear" ) radial = false;
+ else
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.beginGradientFill(%s): first arg must be "
+ "'radial' or 'linear'"),
+ movieclip->getTarget(), ss.str());
+ );
+ return as_value();
+ }
+
+ typedef boost::intrusive_ptr<as_object> ObjPtr;
+
+ ObjPtr colors = fn.arg(1).to_object();
+ ObjPtr alphas = fn.arg(2).to_object();
+ ObjPtr ratios = fn.arg(3).to_object();
+ ObjPtr matrixArg = fn.arg(4).to_object();
+
+ if ( ! colors || ! alphas || ! ratios || ! matrixArg )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.beginGradientFill(%s): one or more of the "
+ " args from 2nd to 5th don't cast to objects"),
+ movieclip->getTarget(), ss.str());
+ );
+ return as_value();
+ }
+
+ // ----------------------------
+ // Parse SWFMatrix
+ // ----------------------------
+
+ //
+ // TODO: fix the SWFMatrix build-up, it is NOT correct for
+ // rotation.
+ // For the "boxed" SWFMatrixType and radial fills this
+ // is not a problem as this code just discards the
+ // rotation (which doesn't make sense), but for
+ // the explicit SWFMatrix type (a..i) it is a problem.
+ // The whole code can likely be simplified by
+ // always transforming the gnash gradients to the
+ // expected gradients and subsequently applying
+ // user-specified SWFMatrix; for 'boxed' SWFMatrixType
+ // this simplification would increas cost, but
+ // it's too early to apply optimizations to the
+ // code (correctness first!!).
+ //
+
+ SWFMatrix mat;
+ SWFMatrix input_matrix;
+
+ if ( matrixArg->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box" )
+ {
+
+ boost::int32_t valX = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_X).to_number());
+ boost::int32_t valY = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_Y).to_number());
+ boost::int32_t valW = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_W).to_number());
+ boost::int32_t valH = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_H).to_number());
+ float valR = matrixArg->getMember(NSV::PROP_R).to_number();
+
+ if ( radial )
+ {
+ // Radial gradient is 64x64 twips.
+ input_matrix.set_scale(64.0/valW, 64.0/valH);
+
+ // For radial gradients, dunno why translation must be negative...
+ input_matrix.concatenate_translation( -valX, -valY );
+
+ // NOTE: rotation is intentionally discarded as it would
+ // have no effect (theoretically origin of the radial
+ // fill is at 0,0 making any rotation meaningless).
+
+ }
+ else
+ {
+ // Linear gradient is 256x1 twips.
+ //
+ // No idea why we should use the 256 value for Y scale, but
+ // empirically seems to give closer results. Note that it only
+ // influences rotation, which is still not correct...
+ // TODO: fix it !
+ input_matrix.set_scale_rotation(256.0/valW, 256.0/valH, -valR);
+
+ // For linear gradients, dunno why translation must be negative...
+ input_matrix.concatenate_translation( -valX, -valY );
+ }
+
+ mat.concatenate(input_matrix);
+ }
+ else
+ {
+ float valA = matrixArg->getMember(NSV::PROP_A).to_number() ; // xx
+ float valB = matrixArg->getMember(NSV::PROP_B).to_number() ; // yx
+ float valD = matrixArg->getMember(NSV::PROP_D).to_number() ; // xy
+ float valE = matrixArg->getMember(NSV::PROP_E).to_number() ; // yy
+ boost::int32_t valG = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_G).to_number()); // x0
+ boost::int32_t valH = pixelsToTwips(
+ matrixArg->getMember(NSV::PROP_H).to_number()); // y0
+
+ input_matrix.sx = valA * 65536; // sx
+ input_matrix.shx = valB * 65536; // shy
+ input_matrix.shy = valD * 65536; // shx
+ input_matrix.sy = valE * 65536; // sy
+ input_matrix.tx = valG; // x0
+ input_matrix.ty = valH; // y0
+
+ // This is the SWFMatrix that would transform the gnash
+ // gradient to the expected flash gradient.
+ // Transformation is different for linear and radial
+ // gradient for Gnash (in flash they should be the same)
+ SWFMatrix gnashToFlash;
+
+ if ( radial )
+ {
+
+ // Gnash radial gradients are 64x64 with center at 32,32
+ // Should be 20x20 with center at 0,0
+ const double g2fs = 20.0/64.0; // gnash to flash scale
+ gnashToFlash.set_scale(g2fs, g2fs);
+ gnashToFlash.concatenate_translation(-32, -32);
+
+ }
+ else
+ {
+ // First define a SWFMatrix that would transform
+ // the gnash gradient to the expected flash gradient:
+ // this means translating our gradient to put the
+ // center of gradient at 0,0 and then scale it to
+ // have a size of 20x20 instead of 256x1 as it is
+ //
+ // Gnash linear gradients are 256x1 with center at 128,0
+ // Should be 20x20 with center at 0,0
+ gnashToFlash.set_scale(20.0/256.0, 20.0/1);
+ gnashToFlash.concatenate_translation(-128, 0);
+
+ }
+
+ // Apply gnash to flash SWFMatrix before user-defined one
+ input_matrix.concatenate(gnashToFlash);
+
+ // Finally, and don't know why, take
+ // the inverse of the resulting SWFMatrix as
+ // the one which would be used.
+ mat = input_matrix;
+ mat.invert();
+ }
+
+ // ----------------------------
+ // Create the gradients vector
+ // ----------------------------
+
+ size_t ngradients = colors->getMember(NSV::PROP_LENGTH).to_int();
+ // Check length compatibility of all args
+ if ( ngradients != (size_t)alphas->getMember(NSV::PROP_LENGTH).to_int() ||
+ ngradients != (size_t)ratios->getMember(NSV::PROP_LENGTH).to_int() )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror(_("%s.beginGradientFill(%s): colors, alphas and "
+ "ratios args don't have same length"),
+ movieclip->getTarget(), ss.str());
+ );
+ return as_value();
+ }
+
+ // TODO: limit ngradients to a max ?
+ if ( ngradients > 8 )
+ {
+ std::stringstream ss; fn.dump_args(ss);
+ log_debug(_("%s.beginGradientFill(%s) : too many array elements"
+ " for colors and ratios (%d), will trim to 8"),
+ movieclip->getTarget(), ss.str(), ngradients);
+ ngradients = 8;
+ }
+
+ VM& vm = movieclip->getVM();
+ string_table& st = vm.getStringTable();
+
+ std::vector<gradient_record> gradients;
+ gradients.reserve(ngradients);
+ for (size_t i=0; i<ngradients; ++i)
+ {
+
+ string_table::key key = st.find(boost::lexical_cast<std::string>(i));
+
+ as_value colVal = colors->getMember(key);
+ boost::uint32_t col = colVal.is_number() ? colVal.to_int() : 0;
+
+ as_value alpVal = alphas->getMember(key);
+ boost::uint8_t alp = alpVal.is_number() ?
+ clamp<int>(alpVal.to_int(), 0, 255) : 0;
+
+ as_value ratVal = ratios->getMember(key);
+ boost::uint8_t rat = ratVal.is_number() ?
+ clamp<int>(ratVal.to_int(), 0, 255) : 0;
+
+ rgba color;
+ color.parseRGB(col);
+ color.m_a = alp;
+
+ gradients.push_back(gradient_record(rat, color));
+ }
+
+ if ( radial )
+ {
+ movieclip->beginRadialGradientFill(gradients, mat);
+ }
+ else
+ {
+ movieclip->beginLinearGradientFill(gradients, mat);
+ }
+
+ LOG_ONCE( log_debug("MovieClip.beginGradientFill() TESTING") );
+ return as_value();
+}
+
+// startDrag([lockCenter:Boolean], [left:Number], [top:Number],
+// [right:Number], [bottom:Number]) : Void`
+as_value
+movieclip_startDrag(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ drag_state st;
+ st.setCharacter( movieclip.get() );
+
+ // mark this DisplayObject is transformed.
+ movieclip->transformedByScript();
+
+ if ( fn.nargs )
+ {
+ st.setLockCentered( fn.arg(0).to_bool() );
+
+ if ( fn.nargs >= 5)
+ {
+ double x0 = fn.arg(1).to_number();
+ double y0 = fn.arg(2).to_number();
+ double x1 = fn.arg(3).to_number();
+ double y1 = fn.arg(4).to_number();
+
+ // check for infinite values
+ bool gotinf = false;
+ if (!isFinite(x0) ) { x0=0; gotinf=true; }
+ if (!isFinite(y0) ) { y0=0; gotinf=true; }
+ if (!isFinite(x1) ) { x1=0; gotinf=true; }
+ if (!isFinite(y1) ) { y1=0; gotinf=true; }
+
+ // check for swapped values
+ bool swapped = false;
+ if ( y1 < y0 )
+ {
+ std::swap(y1, y0);
+ swapped = true;
+ }
+
+ if ( x1 < x0 )
+ {
+ std::swap(x1, x0);
+ swapped = true;
+ }
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( gotinf || swapped ) {
+ std::stringstream ss; fn.dump_args(ss);
+ if ( swapped ) {
+ log_aserror(_("min/max bbox values in "
+ "MovieClip.startDrag(%s) swapped, fixing"),
+ ss.str());
+ }
+ if ( gotinf ) {
+ log_aserror(_("non-finite bbox values in "
+ "MovieClip.startDrag(%s), took as zero"),
+ ss.str());
+ }
+ }
+ );
+
+ rect bounds(pixelsToTwips(x0), pixelsToTwips(y0),
+ pixelsToTwips(x1), pixelsToTwips(y1));
+ st.setBounds(bounds);
+ }
+ }
+
+ movieclip->getVM().getRoot().set_drag_state(st);
+
+ return as_value();
+}
+
+// stopDrag() : Void
+as_value
+movieclip_stopDrag(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> movieclip =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ movieclip->getVM().getRoot().stop_drag();
+
+ return as_value();
+}
+
+
+as_value
+movieclip_beginBitmapFill(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+ LOG_ONCE( log_unimpl (__FUNCTION__) );
+ return as_value();
+}
+
+
+as_value
+movieclip_getRect(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+ LOG_ONCE( log_unimpl (__FUNCTION__) );
+ return as_value();
+}
+
+
+as_value
+movieclip_lineGradientStyle(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+ LOG_ONCE( log_unimpl (__FUNCTION__) );
+ return as_value();
+}
+
+
+as_value
+movieclip_attachBitmap(const fn_call& fn)
+{
+
+ GNASH_REPORT_FUNCTION;
+
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+ if (fn.nargs < 2) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_debug("MovieClip.attachBitmap: expected 2 args, got %d",
+ fn.nargs);
+ );
+ return as_value();
+ }
+
+ as_object* obj = fn.arg(0).to_object().get();
+ boost::intrusive_ptr<BitmapData_as> bd = dynamic_cast<BitmapData_as*>(obj);
+
+ if (!bd) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_debug("MovieClip.attachBitmap: first argument should be a "
+ "BitmapData", fn.arg(1));
+ );
+ return as_value();
+ }
+
+ int depth = fn.arg(1).to_int();
+
+ ptr->attachBitmap(bd, depth);
+
+ return as_value();
+}
+
+
+as_value
+movieclip_as2_ctor(const fn_call& fn)
+{
+
+ assert(!isAS3(fn));
+
+ boost::intrusive_ptr<as_object> clip =
+ new as_object(getMovieClipAS2Interface());
+
+ return as_value(clip.get());
+}
+
+
+as_value
+movieclip_currentFrame(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(std::min(ptr->get_loaded_frames(),
+ ptr->get_current_frame() + 1));
+}
+
+as_value
+movieclip_totalFrames(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(ptr->get_frame_count());
+}
+
+as_value
+movieclip_framesLoaded(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(ptr->get_loaded_frames());
+}
+
+as_value
+movieclip_dropTarget(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+
+ return ptr->getDropTarget();
+}
+
+as_value
+movieclip_url(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+ return as_value(ptr->get_root()->url());
+}
+
+// TODO: move this to DisplayObject class, _focusrect seems a generic property
+as_value
+movieclip_focusRect(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+
+ if ( fn.nargs == 0 ) // getter
+ {
+ // Is a yellow rectangle visible around a focused movie clip (?)
+ // We don't support focuserct settings
+ return as_value(false);
+ }
+ else // setter
+ {
+ LOG_ONCE( log_unimpl("MovieClip._focusrect setting") );
+ }
+ return as_value();
+}
+
+as_value
+movieclip_soundbuftime(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr =
+ ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+
+ if ( fn.nargs == 0 ) // getter
+ {
+ // Number of seconds before sound starts to stream.
+ return as_value(0.0);
+ }
+ else // setter
+ {
+ LOG_ONCE( log_unimpl("MovieClip._soundbuftime setting") );
+ }
+ return as_value();
+}
+
+as_value
+movieclip_transform(const fn_call& fn)
+{
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+ // If not found, construction fails.
+ as_value transform(fn.env().find_object("flash.geom.Transform"));
+
+ boost::intrusive_ptr<as_function> transCtor = transform.to_as_function();
+
+ if (!transCtor) {
+ log_error("Failed to construct flash.geom.Transform!");
+ return as_value();
+ }
+
+ // Construct a flash.geom.Transform object with "this" as argument.
+ std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+ args->push_back(ptr.get());
+
+ boost::intrusive_ptr<as_object> newTrans =
+ transCtor->constructInstance(fn.env(), args);
+
+ return as_value(newTrans.get());
+}
+
+// =======================
+// AS3 interface
+// =======================
+
+as_value
+movieclip_as3_ctor(const fn_call& fn)
+{
+ assert(isAS3(fn));
+
+ log_unimpl("AVM2 MovieClip ctor");
+
+ return as_value();
+}
+
+
+void
+attachMovieClipAS3Interface(as_object& o)
{
o.init_member("gotoAndStop", new builtin_function(movieclip_gotoAndStop));
o.init_member("nextFrame", new builtin_function(movieclip_nextFrame));
@@ -85,68 +2653,10 @@
o.init_member("stop", new builtin_function(movieclip_stop));
}
-void
-attachMovieClipStaticInterface(as_object& o)
-{
-
-}
-
-as_object*
-getMovieClipInterface()
-{
- static boost::intrusive_ptr<as_object> o;
- if ( ! o ) {
- o = new as_object();
- attachMovieClipInterface(*o);
- }
- return o.get();
-}
-
-as_value
-movieclip_gotoAndStop(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-movieclip_nextFrame(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
as_value
movieclip_nextScene(const fn_call& fn)
{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-movieclip_play(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-movieclip_prevFrame(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
UNUSED(ptr);
log_unimpl (__FUNCTION__);
return as_value();
@@ -155,29 +2665,10 @@
as_value
movieclip_prevScene(const fn_call& fn)
{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-movieclip_stop(const fn_call& fn)
-{
- boost::intrusive_ptr<MovieClip_as> ptr =
- ensureType<MovieClip_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-movieclip_ctor(const fn_call& fn)
-{
- boost::intrusive_ptr<as_object> obj = new MovieClip_as;
-
- return as_value(obj.get()); // will keep alive
+ boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+ UNUSED(ptr);
+ log_unimpl (__FUNCTION__);
+ return as_value();
}
} // anonymous namespace
=== modified file 'libcore/asobj/flash/display/MovieClip_as.h'
--- a/libcore/asobj/flash/display/MovieClip_as.h 2009-05-28 17:29:17
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.h 2009-06-04 06:53:55
+0000
@@ -25,17 +25,29 @@
#endif
+namespace gnash {
+
// Forward declarations
class as_object;
-
-namespace gnash {
+class DisplayObject;
/// Initialize the global MovieClip class
void movieclip_class_init(as_object& global);
+/// Get an as_object with the AS3 MovieClip interface.
+as_object* getMovieClipAS3Interface();
+
+/// Register ASNative MovieClip methods (AS2 only).
+void registerMovieClipNative(as_object& global);
+
+/// Used by MovieClip's ctor to attach properties to MovieClip instances.
+void attachMovieClipAS2Properties(DisplayObject& d);
+
+/// Get an as_object with the AS2 MovieClip interface.
+as_object* getMovieClipAS2Interface();
+
} // gnash namespace
-// GNASH_ASOBJ3_MOVIECLIP_H
#endif
// local Variables:
=== modified file 'libcore/asobj/flash/display/display.am'
--- a/libcore/asobj/flash/display/display.am 2009-06-12 03:21:00 +0000
+++ b/libcore/asobj/flash/display/display.am 2009-06-16 05:42:44 +0000
@@ -123,10 +123,10 @@
DISPLAY_HEADERS += asobj/flash/display/MorphShape_as.h
endif
-# FIXME: already exists
-# DISPLAY_SOURCES += asobj/flash/display/MovieClip_as.cpp
+if BUILD_MOVIECLIP_AS3
+DISPLAY_SOURCES += asobj/flash/display/MovieClip_as.cpp
DISPLAY_HEADERS += asobj/flash/display/MovieClip_as.h
-# endif
+endif
if BUILD_PIXELSNAPPING_AS3
DISPLAY_SOURCES += asobj/flash/display/PixelSnapping_as.cpp
=== modified file 'libcore/vm/Machine.cpp'
--- a/libcore/vm/Machine.cpp 2009-06-15 06:59:31 +0000
+++ b/libcore/vm/Machine.cpp 2009-06-16 06:51:59 +0000
@@ -269,30 +269,6 @@
}
-Machine::Machine(VM& vm)
- :
- mStack(),
- mRegisters(),
- mScopeStack(),
- mStream(0),
- mST(vm.getStringTable()),
- mDefaultXMLNamespace(0),
- mCurrentScope(0),
- mGlobalScope(0),
- mDefaultThis(0),
- mThis(0),
- mGlobalObject(0),
- mGlobalReturn(),
- mIgnoreReturn(),
- mIsAS3(false),
- mExitWithReturn(false),
- mPoolObject(0),
- mCurrentFunction(0),
- _vm(vm),
- mCH(_vm.getClassHierarchy())
-{
-}
-
void
Machine::execute()
{
@@ -363,8 +339,11 @@
mStack.drop(completeName(a));
// Get the target object.
ENSURE_OBJECT(mStack.top(0));
+
+ // Use get_super?
as_object *super = mStack.top(0).to_object()->
get_prototype().get();
+
// If we don't have a super, throw.
if (!super) throw ASReferenceError();
Property *b = super->findProperty(a.getABCName(),
@@ -392,6 +371,8 @@
mStack.drop(completeName(a));
ENSURE_OBJECT(mStack.top(0));
+
+ // Use get_super?
as_object* super = mStack.pop().to_object()->
get_prototype().get();
if (!super) throw ASReferenceError();
@@ -1259,7 +1240,11 @@
int dropsize = completeName(a);
ENSURE_OBJECT(mStack.top(argc + dropsize));
mStack.drop(dropsize);
- as_object* super =
mStack.top(argc).to_object()->get_super();
+
+ // Why get_super() here and get_prototype everywhere else?
+ as_object* super =
+ mStack.top(argc).to_object()->get_super();
+
if (!super) throw ASReferenceError();
Property* b = super->findProperty(a.getABCName(),
@@ -1301,10 +1286,11 @@
as_value result;
asName a = pool_name(mStream->read_V32(), mPoolObject);
boost::uint32_t argc = mStream->read_V32();
- std::auto_ptr<std::vector<as_value> > args =
get_args(argc);
-
+ std::auto_ptr< std::vector<as_value> > args =
get_args(argc);
+ //TODO: If multiname is runtime also pop namespace and/or
name values.
+
if (a.isRuntime()) {
- mStack.drop(completeName(a));
+ log_unimpl("ABC_ACTION_CALL* with runtime multiname");
}
as_value object_val = pop_stack();
@@ -1312,31 +1298,31 @@
as_object *object = object_val.to_object().get();
if (!object) {
IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Can't call a method of a value that "
- "doesn't cast to an object (%s)."),
+ log_aserror(_("Can't call a method of a value that
doesn't "
+ "cast to an object (%s)."),
object_val);
)
}
else {
- as_value property = object->getMember(
- a.getGlobalName(), 0);
+ as_value property =
object->getMember(a.getGlobalName(), 0);
if (!property.is_undefined() && !property.is_null()) {
log_abc("Calling method %s on object %s",
- property, object_val);
+
property.toDebugString(),object_val.toDebugString());
as_environment env = as_environment(_vm);
result = call_method(property,env,object,args);
}
else {
IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Property '%s' of object '%s' is "
- "'%s', cannot call as method"),
+ log_aserror(_("Property '%s' of object '%s' is
'%s', "
+ "cannot call as method"),
mPoolObject->stringPoolAt(a.getABCName()),
object_val, property);
)
}
+
}
if (opcode == SWF::ABC_ACTION_CALLPROPERTY) {
@@ -1420,7 +1406,10 @@
get_args(argc);
as_object* obj = mStack.top(argc).to_object().get();
- as_object* super = obj ? obj->get_super() : 0;
+
+ // Using get_super() here fails; is it broken, or is
+ // prototype what we want?
+ as_object* super = obj ? obj->get_prototype().get() : 0;
log_abc("CONSTRUCTSUPER: object %s, super %s, args %s",
mStack.top(argc), super, argc);
@@ -1429,11 +1418,11 @@
throw ASException();
}
- as_function *func = super->get_constructor();
+ as_function *func = super->to_function();
if (!func) {
log_abc("CONSTRUCTSUPER: %s has no constructor",
super);
- return;
+ break;
}
// 'obj' is the 'this' for the call, we ignore the
@@ -1563,14 +1552,15 @@
push_stack(as_value(mCurrentFunction));
break;
}
+
/// 0x58 ABC_ACTION_NEWCLASS
/// Stream: V32 'class_id'
/// Stack In:
/// obj -- An object to be turned into a class. Its super
/// is constructed.
/// Stack Out:
- /// class -- The newly made class, made from obj and the "
- /// "information at cinits_pool[class_id]
+ /// class -- The newly made class, made from obj and the
+ /// information at cinits_pool[class_id]
/// NB: This depends on scope and scope base (to determine
/// lifetime(?))
case SWF::ABC_ACTION_NEWCLASS:
@@ -1595,19 +1585,14 @@
new_class->init_member(NSV::PROP_uuCONSTRUCTORuu,
as_value(static_constructor), 0);
- as_function* constructor =
- c->getConstructor()->getPrototype();
- new_class->init_member(NSV::PROP_CONSTRUCTOR,
- constructor, 0);
- push_stack(new_class);
+ as_function* constructor =
c->getConstructor()->getPrototype();
+ new_class->init_member(NSV::PROP_CONSTRUCTOR,
as_value(constructor), 0);
+ push_stack(as_value(new_class));
- // Call the class's static constructor (which may be
- // undefined).
+ // Call the class's static constructor (which may be
undefined).
as_environment env = as_environment(_vm);
- as_value property = new_class->getMember(
- NSV::PROP_uuCONSTRUCTORuu, 0);
- as_value value = call_method(property, env, new_class,
- get_args(0));
+ as_value property =
new_class->getMember(NSV::PROP_uuCONSTRUCTORuu, 0);
+ as_value value = call_method(property, env, new_class,
get_args(0));
break;
}
@@ -1700,8 +1685,6 @@
{
asName a = pool_name(mStream->read_V32(), mPoolObject);
- // This pushes a value onto the stack, but it seems
- // we don't need it.
as_value val = find_prop_strict(a);
log_abc("GETLEX: found value %s", val);
@@ -1834,13 +1817,10 @@
as_value object_val = pop_stack();
as_object* object = object_val.to_object().get();
-
- log_abc(_("ABC_ACTION_GETPROPERTY: Looking for property "
- "%s of object %s"), mST.value(name), object_val);
-
+
if (!object) {
- log_abc(_("ABC_ACTION_GETPROPERTY: expecting "
- "object on stack, got %s."), object_val);
+ log_abc(_("GETPROPERTY: expecting object on "
+ "stack, got %s."), object_val);
push_stack(as_value());
break;
}
@@ -1934,6 +1914,11 @@
as_value val;
boost::uint32_t sindex = mStream->read_V32();
as_object* object = pop_stack().to_object().get();
+ if (!object) {
+ log_abc("GETSLOT: Did not find expected object on "
+ "stack");
+ break;
+ }
object->get_member_slot(sindex + 1, &val);
@@ -2574,9 +2559,10 @@
if (!valueObject || !typeObject) {
// TODO: what here!?
// This should eventually be a malformed SWF error.
- log_error("ACTION_ISTYPELATE: require two objects on
stack, got "
- "obj: %s, type: %s.", value, type);
- return;
+ log_error("ACTION_ISTYPELATE: require two objects "
+ "on stack, got obj: %s, type: %s.",
+ value, type);
+ break;
}
const bool truth = valueObject->instanceOf(typeObject);
push_stack(truth);
@@ -3062,16 +3048,41 @@
// is to be constructed. Setting it to global as before seems to be wrong.
mRegisters[0] = cl->getPrototype();
executeCodeblock(ctor->getBody());
-
log_debug("Finished instantiating class %s", className);
}
+Machine::Machine(VM& vm)
+ :
+ mStack(),
+ mRegisters(),
+ mScopeStack(),
+ mStream(0),
+ mST(vm.getStringTable()),
+ mDefaultXMLNamespace(0),
+ mCurrentScope(0),
+ mGlobalScope(0),
+ mDefaultThis(0),
+ mThis(0),
+ mGlobalObject(0),
+ mGlobalReturn(),
+ mIgnoreReturn(),
+ mIsAS3(false),
+ mExitWithReturn(false),
+ mPoolObject(0),
+ mCurrentFunction(0),
+ _vm(vm),
+ mCH(_vm.getClassHierarchy())
+{
+ //Local registers should be initialized at the beginning of each
function call, but
+ //we don't currently parse the number of local registers for each
function.
+// mRegisters.resize(16);
+// mST = new string_table();
+// mST = ST;
+}
+
as_value
-Machine::find_prop_strict(asName multiname)
-{
-
- log_abc("Looking for property %s", mST.value(multiname.getGlobalName()));
-
+Machine::find_prop_strict(asName multiname) {
+
as_value val;
mScopeStack.push(mGlobalObject);
for (size_t i = 0; i < mScopeStack.size(); ++i)
@@ -3091,17 +3102,16 @@
}
}
- as_object* target = 0;
+ log_abc("Cannot find property in scope stack. Trying again using "
+ "as_environment.");
+ as_object *target = NULL;
as_environment env = as_environment(_vm);
std::string name = mPoolObject->stringPoolAt(multiname.getABCName());
std::string ns = mPoolObject->stringPoolAt(
multiname.getNamespace()->getAbcURI());
std::string path = ns.empty() ? name : ns + "." + name;
-
- log_abc("Failed to find property in scope stack. Looking for %s in "
- "as_environment", path);
- std::auto_ptr<as_environment::ScopeStack> envStack (getScopeStack());
+ std::auto_ptr<as_environment::ScopeStack> envStack ( getScopeStack() );
val = env.get_variable(path, *envStack, &target);
push_stack(target);
=== modified file 'libcore/vm/VM.h'
--- a/libcore/vm/VM.h 2009-06-03 16:05:40 +0000
+++ b/libcore/vm/VM.h 2009-06-04 06:48:54 +0000
@@ -352,6 +352,13 @@
};
+/// Return true if the VM is executing AS3 (ABC bytecode).
+inline bool
+isAS3(VM& vm)
+{
+ return vm.getAVMVersion() == VM::AVM2;
+}
+
} // namespace gnash
#endif // GNASH_VM_H
=== modified file 'testsuite/as3/dejagnu.as'
--- a/testsuite/as3/dejagnu.as 2009-06-15 16:42:47 +0000
+++ b/testsuite/as3/dejagnu.as 2009-06-16 06:35:15 +0000
@@ -19,9 +19,8 @@
package dejagnu {
import flash.text.*;
- import flash.display.Sprite;
- public class Dejagnu extends Sprite {
+ public class Dejagnu {
private static var passed = 0;
private static var failed = 0;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r11125: Add an AS3 MovieClip interface. Move the AS functions into,
Benjamin Wolsey <=