[Swfdec] 22 commits - libswfdec/js libswfdec/swfdec_debugger.c libswfdec/swfdec_js.c libswfdec/swfdec_js_global.c libswfdec/swfdec_js_movie.c libswfdec/swfdec_movie.c libswfdec/swfdec_player.c libswfdec/swfdec_player_internal.h libswfdec/swfdec_script.c libswfdec/swfdec_script.h libswfdec/swfdec_tag.c player/swfdec_debug_script.c test/trace

Benjamin Otte company at kemper.freedesktop.org
Mon Feb 19 11:35:48 PST 2007


 libswfdec/js/jsfun.c                    |    7 +
 libswfdec/js/jsobj.c                    |   12 +-
 libswfdec/swfdec_debugger.c             |    5 
 libswfdec/swfdec_js.c                   |   10 +
 libswfdec/swfdec_js_global.c            |  165 +++++++++++++++++++++++++++++++-
 libswfdec/swfdec_js_movie.c             |   51 +++++++--
 libswfdec/swfdec_movie.c                |    8 +
 libswfdec/swfdec_player.c               |   23 +---
 libswfdec/swfdec_player_internal.h      |    3 
 libswfdec/swfdec_script.c               |   77 +++++++++-----
 libswfdec/swfdec_script.h               |    2 
 libswfdec/swfdec_tag.c                  |    1 
 player/swfdec_debug_script.c            |    2 
 test/trace/Makefile.am                  |   14 ++
 test/trace/function-undefined.swf       |binary
 test/trace/function-undefined.swf.trace |    2 
 test/trace/local.swf                    |binary
 test/trace/local.swf.trace              |    3 
 test/trace/parent-root.swf              |binary
 test/trace/parent-root.swf.trace        |    2 
 test/trace/preload.swf                  |binary
 test/trace/preload.swf.trace            |    4 
 test/trace/setinterval-clear.swf        |binary
 test/trace/setinterval-clear.swf.trace  |    3 
 test/trace/setinterval.swf              |binary
 test/trace/setinterval.swf.trace        |   21 ++++
 test/trace/setinterval2.swf             |binary
 test/trace/setinterval2.swf.trace       |    5 
 28 files changed, 356 insertions(+), 64 deletions(-)

New commits:
diff-tree 185d07d2ed05ec0bf1970484d27642703177702e (from a3a877f6e2f219f403100c3d994bccd3a2cc72bc)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 20:35:26 2007 +0100

    add test for local scope using DefineLocal

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 4d11f13..ea517f7 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -74,6 +74,8 @@ EXTRA_DIST = \
 	load-4.swf.trace \
 	load-5.swf \
 	load-5.swf.trace \
+	local.swf \
+	local.swf.trace \
 	name.swf \
 	name.swf.trace \
 	name2.swf \
diff --git a/test/trace/local.swf b/test/trace/local.swf
new file mode 100755
index 0000000..0c3d5ab
Binary files /dev/null and b/test/trace/local.swf differ
diff --git a/test/trace/local.swf.trace b/test/trace/local.swf.trace
new file mode 100755
index 0000000..9aaac5c
--- /dev/null
+++ b/test/trace/local.swf.trace
@@ -0,0 +1,3 @@
+Test behaviour of DefineLocal
+7
+undefined
diff-tree a3a877f6e2f219f403100c3d994bccd3a2cc72bc (from a986921e1731e82386bbeb8bd5e2e765acc58c6b)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 20:33:56 2007 +0100

    It looks like Flash doesn't create a local scope for the entry scripts, so don't do it either
    
    the good thing about this: make check passes

diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c
index 9d6782a..e6ce8a5 100644
--- a/libswfdec/swfdec_js.c
+++ b/libswfdec/swfdec_js.c
@@ -338,7 +338,7 @@ swfdec_js_eval_set_property (JSContext *
   if (obj == NULL) {
     if (cx->fp == NULL || cx->fp->scopeChain == NULL)
       return JS_FALSE;
-    obj = JS_GetParent (cx, cx->fp->scopeChain);
+    obj = cx->fp->thisp;
   }
   return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret);
 }
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index d46687f..824861b 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1643,11 +1643,11 @@ swfdec_action_define_local (JSContext *c
 {
   const char *name;
 
-  g_assert (cx->fp->callobj != NULL);
+  g_assert (cx->fp->scopeChain != NULL);
   name = swfdec_js_to_string (cx, cx->fp->sp[-2]);
   if (name == NULL)
     return JS_FALSE;
-  if (!JS_SetProperty (cx, cx->fp->callobj, name, &cx->fp->sp[-1]))
+  if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &cx->fp->sp[-1]))
     return JS_FALSE;
   cx->fp->sp -= 2;
   return JS_TRUE;
@@ -1659,11 +1659,11 @@ swfdec_action_define_local2 (JSContext *
   const char *name;
   jsval val = JSVAL_VOID;
 
-  g_assert (cx->fp->callobj != NULL);
+  g_assert (cx->fp->scopeChain != NULL);
   name = swfdec_js_to_string (cx, cx->fp->sp[-1]);
   if (name == NULL)
     return JS_FALSE;
-  if (!JS_SetProperty (cx, cx->fp->callobj, name, &val))
+  if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &val))
     return JS_FALSE;
   cx->fp->sp--;
   return JS_TRUE;
@@ -2593,9 +2593,9 @@ swfdec_script_execute (SwfdecScript *scr
     return JSVAL_VOID;
   oldfp = cx->fp;
 
-  frame.callobj = frame.argsobj = NULL;
+  frame.callobj = NULL;
   frame.script = NULL;
-  frame.varobj = NULL;
+  frame.varobj = frame.argsobj = NULL;
   frame.fun = swfdec_script_ensure_function (script, scriptable);
   frame.swf = script;
   frame.constant_pool = NULL;
@@ -2606,7 +2606,6 @@ swfdec_script_execute (SwfdecScript *scr
   frame.sharpArray = NULL;
   frame.rval = JSVAL_VOID;
   frame.down = NULL;
-  frame.scopeChain = NULL;
   frame.pc = NULL;
   frame.sp = oldfp ? oldfp->sp : NULL;
   frame.spbase = NULL;
@@ -2614,7 +2613,8 @@ swfdec_script_execute (SwfdecScript *scr
   frame.flags = 0;
   frame.dormantNext = NULL;
   frame.objAtomMap = NULL;
-
+  /* no local scope here */
+  frame.scopeChain = obj;
   /* allocate stack for variables */
   frame.nvars = 4;
   frame.vars = js_AllocStack (cx, frame.nvars, &mark);
@@ -2622,9 +2622,6 @@ swfdec_script_execute (SwfdecScript *scr
     return JS_FALSE;
   }
   frame.vars[0] = frame.vars[1] = frame.vars[2] = frame.vars[3] = JSVAL_VOID;
-  /* create a call object */
-  if (!js_GetCallObject(cx, &frame, obj))
-    return JS_FALSE;
 
   if (oldfp) {
     g_assert (!oldfp->dormantNext);
@@ -2643,11 +2640,6 @@ swfdec_script_execute (SwfdecScript *scr
   if (frame.constant_pool)
     swfdec_constant_pool_free (frame.constant_pool);
 
-  if (frame.callobj)
-    ok &= js_PutCallObject(cx, &frame);
-  if (frame.argsobj)
-    ok &= js_PutArgsObject(cx, &frame);
-
   cx->fp = oldfp;
   if (oldfp) {
     g_assert (cx->dormantFrameChain == oldfp);
diff-tree a986921e1731e82386bbeb8bd5e2e765acc58c6b (from 8a66540298c89725624385a022580e593d6da3a4)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 18:47:46 2007 +0100

    implement setInterval and clearInterval

diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c
index 481ec48..9d6782a 100644
--- a/libswfdec/swfdec_js.c
+++ b/libswfdec/swfdec_js.c
@@ -113,6 +113,8 @@ swfdec_js_init_player (SwfdecPlayer *pla
   swfdec_js_add_sound (player);
 }
 
+typedef struct _SwfdecJSInterval SwfdecJSInterval;
+extern void swfdec_js_interval_free (SwfdecJSInterval *interval);
 /**
  * swfdec_js_finish_player:
  * @player: a #SwfdecPlayer
@@ -122,6 +124,8 @@ swfdec_js_init_player (SwfdecPlayer *pla
 void
 swfdec_js_finish_player (SwfdecPlayer *player)
 {
+  while (player->intervals)
+    swfdec_js_interval_free (player->intervals->data);
   if (player->jscx) {
     JS_DestroyContext(player->jscx);
     player->jsobj = NULL;
diff --git a/libswfdec/swfdec_js_global.c b/libswfdec/swfdec_js_global.c
index 328d74d..06e83e1 100644
--- a/libswfdec/swfdec_js_global.c
+++ b/libswfdec/swfdec_js_global.c
@@ -1,5 +1,5 @@
 /* Swfdec
- * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2006-2007 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,159 @@
 #include "swfdec_js.h"
 #include "swfdec_debug.h"
 #include "swfdec_player_internal.h"
+#include "js/jsatom.h"
+#include "js/jsfun.h"
+#include "js/jsinterp.h"
+#include "js/jsobj.h"
+
+/*** INTERVAL ***/
+
+typedef struct _SwfdecJSInterval SwfdecJSInterval;
+struct _SwfdecJSInterval {
+  SwfdecTimeout		timeout;
+  SwfdecPlayer *	player;		/* needed so it can be readded */
+  unsigned int		id;		/* id this interval is identified with */
+  unsigned int		msecs;		/* interval in milliseconds */
+  unsigned int		n_args;		/* number of arguments to call function with */
+  jsval			vals[0];	/* values: 0 is function, 1 is object, 2-n are arguments */
+};
+
+void
+swfdec_js_interval_free (SwfdecJSInterval *interval)
+{
+  JSContext *cx = interval->player->jscx;
+  guint i;
+
+  swfdec_player_remove_timeout (interval->player, &interval->timeout);
+  interval->player->intervals = 
+    g_list_remove (interval->player->intervals, interval);
+  for (i = 0; i < interval->n_args + 2; i++) {
+    JS_RemoveRoot (cx, &interval->vals[i]);
+  }
+  g_free (interval);
+}
+
+static void
+swfdec_js_interval_trigger (SwfdecTimeout *timeout)
+{
+  SwfdecJSInterval *interval = (SwfdecJSInterval *) timeout;
+  JSContext *cx = interval->player->jscx;
+  jsval fun, rval;
+
+  timeout->timestamp += SWFDEC_MSECS_TO_TICKS (interval->msecs);
+  swfdec_player_add_timeout (interval->player, timeout);
+  g_assert (JSVAL_IS_OBJECT (interval->vals[1]));
+  if (JSVAL_IS_STRING (interval->vals[0])) {
+    JSAtom *atom = js_AtomizeString (cx, JSVAL_TO_STRING (interval->vals[0]), 0);
+    if (!atom)
+      return;
+    if (!js_GetProperty (cx, JSVAL_TO_OBJECT (interval->vals[1]),
+	  (jsid) atom, &fun))
+      return;
+  } else {
+    fun = interval->vals[0];
+  }
+  js_InternalCall (cx, JSVAL_TO_OBJECT (interval->vals[1]), fun,
+      interval->n_args, &interval->vals[2], &rval);
+}
+
+static SwfdecJSInterval *
+swfdec_js_interval_new (guint n_args)
+{
+  SwfdecJSInterval *ret = g_malloc (sizeof (SwfdecJSInterval) + sizeof (jsval) * (2 + n_args));
+
+  ret->timeout.callback = swfdec_js_interval_trigger;
+  ret->n_args = n_args;
+  return ret;
+}
+
+static JSBool
+swfdec_js_global_setInterval (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  SwfdecPlayer *player = JS_GetContextPrivate (cx);
+  JSObject *object;
+  jsval fun;
+  unsigned int i, n_args, first_arg, msecs;
+  SwfdecJSInterval *interval;
+
+  if (!JSVAL_IS_OBJECT (argv[0])) {
+    SWFDEC_WARNING ("first argument to setInterval is not an object");
+    return JS_TRUE;
+  }
+  object = JSVAL_TO_OBJECT (argv[0]);
+  if (JS_GetClass (object) == &js_FunctionClass) {
+    fun = argv[0];
+    object = JS_GetParent (cx, object);
+    if (object == NULL) {
+      SWFDEC_WARNING ("function has no parent?!");
+      return JS_TRUE;
+    }
+    first_arg = 2;
+  } else {
+    if (argc < 3) {
+      SWFDEC_WARNING ("setInterval needs 3 arguments when not called with function");
+      return JS_TRUE;
+    }
+    if (!JSVAL_IS_STRING (argv[1])) {
+      SWFDEC_WARNING ("function name passed to setInterval is not a string");
+      return JS_TRUE;
+    }
+    fun = argv[1];
+    first_arg = 3;
+  }
+  if (!JS_ValueToECMAUint32 (cx, argv[first_arg - 1], &msecs))
+    return JS_FALSE;
+#define MIN_INTERVAL_TIME 10
+  if (msecs < MIN_INTERVAL_TIME) {
+    SWFDEC_INFO ("interval duration is %u, making it %u msecs", msecs, MIN_INTERVAL_TIME);
+    msecs = MIN_INTERVAL_TIME;
+  }
+  n_args = argc - first_arg;
+  interval = swfdec_js_interval_new (n_args);
+  interval->player = player;
+  interval->id = ++player->interval_id;
+  interval->msecs = msecs;
+  interval->vals[0] = fun;
+  interval->vals[1] = OBJECT_TO_JSVAL (object);
+  memcpy (&interval->vals[2], &argv[first_arg], n_args);
+  for (i = 0; i < n_args + 2; i++) {
+    if (!JS_AddRoot (cx, &interval->vals[i])) {
+      /* FIXME: is it save roots that weren't added before? */
+      swfdec_js_interval_free (interval);
+      return JS_FALSE;
+    }
+  }
+  interval->timeout.timestamp = player->time + SWFDEC_MSECS_TO_TICKS (interval->msecs);
+  swfdec_player_add_timeout (player, &interval->timeout);
+  interval->player->intervals = 
+    g_list_prepend (interval->player->intervals, interval);
+  *rval = INT_TO_JSVAL (interval->id);
+  return JS_TRUE;
+}
+
+static JSBool
+swfdec_js_global_clearInterval (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  SwfdecPlayer *player = JS_GetContextPrivate (cx);
+  guint id;
+  GList *walk;
+
+  if (!JSVAL_IS_INT (argv[0])) {
+    SWFDEC_WARNING ("argument is not an int");
+    return JS_TRUE;
+  }
+  id = JSVAL_TO_INT (argv[0]);
+  for (walk = player->intervals; walk; walk = walk->next) {
+    SwfdecJSInterval *interval = walk->data;
+    if (interval->id != id)
+      continue;
+    swfdec_js_interval_free (interval);
+    break;
+  }
+  return JS_TRUE;
+}
+
+/*** VARIOUS ***/
 
 JSBool
 swfdec_js_global_eval (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
@@ -80,10 +233,12 @@ swfdec_js_stopAllSounds (JSContext *cx, 
 }
 
 static JSFunctionSpec global_methods[] = {
-  { "eval",		swfdec_js_global_eval,	1, 0, 0 },
-  { "random",		swfdec_js_random,	1, 0, 0 },
-  { "stopAllSounds",	swfdec_js_stopAllSounds,0, 0, 0 },
-  { "trace",     	swfdec_js_trace,	1, 0, 0 },
+  { "clearInterval",	swfdec_js_global_clearInterval,	1, 0, 0 },
+  { "eval",		swfdec_js_global_eval,		1, 0, 0 },
+  { "random",		swfdec_js_random,		1, 0, 0 },
+  { "setInterval",	swfdec_js_global_setInterval,	2, 0, 0 },
+  { "stopAllSounds",	swfdec_js_stopAllSounds,	0, 0, 0 },
+  { "trace",     	swfdec_js_trace,		1, 0, 0 },
   { NULL, NULL, 0, 0, 0 }
 };
 
diff --git a/libswfdec/swfdec_player_internal.h b/libswfdec/swfdec_player_internal.h
index 7aa499d..ebc5fe9 100644
--- a/libswfdec/swfdec_player_internal.h
+++ b/libswfdec/swfdec_player_internal.h
@@ -80,6 +80,8 @@ struct _SwfdecPlayer
   /* iterating */
   GList *		movies;			/* list of all moveis that want to be iterated */
   SwfdecRingBuffer *	actions;		/* all actions we've queued up so far */
+  unsigned int		interval_id;		/* id returned from setInterval call */
+  GList *		intervals;		/* all currently running intervals */
 };
 
 struct _SwfdecPlayerClass
diff-tree 8a66540298c89725624385a022580e593d6da3a4 (from 06ed0ce6ffaa57e8b70054dcf0c1d3f3dcc0adb0)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 18:47:21 2007 +0100

    add tests for setInterval/clearInterval

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 1330d92..4d11f13 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -100,6 +100,12 @@ EXTRA_DIST = \
 	scope.swf.trace \
 	scope2.swf \
 	scope2.swf.trace \
+	setinterval.swf \
+	setinterval.swf.trace
+	setinterval2.swf \
+	setinterval2.swf.trace \
+	setinterval-clear.swf \
+	setinterval-clear.swf.trace \
 	setvariable.swf \
 	setvariable.swf.trace \
 	transform.swf \
diff --git a/test/trace/setinterval-clear.swf b/test/trace/setinterval-clear.swf
new file mode 100755
index 0000000..963a581
Binary files /dev/null and b/test/trace/setinterval-clear.swf differ
diff --git a/test/trace/setinterval-clear.swf.trace b/test/trace/setinterval-clear.swf.trace
new file mode 100755
index 0000000..38e2f4a
--- /dev/null
+++ b/test/trace/setinterval-clear.swf.trace
@@ -0,0 +1,3 @@
+Test clearInterval works
+1
+2
diff --git a/test/trace/setinterval.swf b/test/trace/setinterval.swf
new file mode 100755
index 0000000..2cda24a
Binary files /dev/null and b/test/trace/setinterval.swf differ
diff --git a/test/trace/setinterval.swf.trace b/test/trace/setinterval.swf.trace
new file mode 100755
index 0000000..4f6bc44
--- /dev/null
+++ b/test/trace/setinterval.swf.trace
@@ -0,0 +1,21 @@
+Test setInterval works
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
+tick: 1
+tick: 3
diff --git a/test/trace/setinterval2.swf b/test/trace/setinterval2.swf
new file mode 100755
index 0000000..c768b9e
Binary files /dev/null and b/test/trace/setinterval2.swf differ
diff --git a/test/trace/setinterval2.swf.trace b/test/trace/setinterval2.swf.trace
new file mode 100755
index 0000000..54adc6e
--- /dev/null
+++ b/test/trace/setinterval2.swf.trace
@@ -0,0 +1,5 @@
+Test some error conditions of setInterval
+undefined
+1
+hi
+boo
diff-tree 06ed0ce6ffaa57e8b70054dcf0c1d3f3dcc0adb0 (from 23a6d3a178edeb4b3f0c822f6e4eafb880b2d561)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 18:45:18 2007 +0100

    add check to ensure preloading works

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 73bded0..1330d92 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -92,6 +92,8 @@ EXTRA_DIST = \
 	order.swf.trace \
 	parent-root.swf \
 	parent-root.swf.trace \
+	preload.swf \
+	preload.swf.trace \
 	rotation-5.swf \
 	rotation-5.swf.trace \
 	scope.swf \
diff --git a/test/trace/preload.swf b/test/trace/preload.swf
new file mode 100755
index 0000000..c613e65
Binary files /dev/null and b/test/trace/preload.swf differ
diff --git a/test/trace/preload.swf.trace b/test/trace/preload.swf.trace
new file mode 100755
index 0000000..7e648bf
--- /dev/null
+++ b/test/trace/preload.swf.trace
@@ -0,0 +1,4 @@
+_level0
+
+_level0
+
diff-tree 23a6d3a178edeb4b3f0c822f6e4eafb880b2d561 (from 77b34b229da25f92968a27d4ed759f154b6519b2)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 18:44:59 2007 +0100

    Freeing of timeouts doesn't work - revert to old system

diff --git a/libswfdec/swfdec_player.c b/libswfdec/swfdec_player.c
index 0b52aeb..0717ff5 100644
--- a/libswfdec/swfdec_player.c
+++ b/libswfdec/swfdec_player.c
@@ -101,20 +101,6 @@ swfdec_player_get_next_event_time (Swfde
   }
 }
 
-static int
-swfdec_timeout_compare (gconstpointer a, gconstpointer b)
-{
-  const SwfdecTimeout *ta = a;
-  const SwfdecTimeout *tb = b;
-
-  /* FIXME: not overflow-safe */
-  if (ta->timestamp < tb->timestamp)
-    return -1;
-  if (ta->timestamp > tb->timestamp)
-    return 1;
-  return 0;
-}
-
 /**
  * swfdec_player_add_timeout:
  * @player: a #SwfdecPlayer
@@ -143,6 +129,7 @@ swfdec_timeout_compare (gconstpointer a,
 void
 swfdec_player_add_timeout (SwfdecPlayer *player, SwfdecTimeout *timeout)
 {
+  GList *walk;
   SwfdecTick next_tick;
 
   g_return_if_fail (SWFDEC_IS_PLAYER (player));
@@ -152,7 +139,13 @@ swfdec_player_add_timeout (SwfdecPlayer 
 
   SWFDEC_LOG ("adding timeout %p", timeout);
   next_tick = swfdec_player_get_next_event_time (player);
-  player->timeouts = g_list_insert_sorted (player->timeouts, timeout, swfdec_timeout_compare);
+  /* the order is important, on events with the same time, we make sure the new one is last */
+  for (walk = player->timeouts; walk; walk = walk->next) {
+    SwfdecTimeout *cur = walk->data;
+    if (cur->timestamp > timeout->timestamp)
+      break;
+  }
+  player->timeouts = g_list_insert_before (player->timeouts, walk, timeout);
   if (next_tick != swfdec_player_get_next_event_time (player))
     g_object_notify (G_OBJECT (player), "next-event");
 }
@@ -329,7 +322,6 @@ swfdec_player_set_property (GObject *obj
 static void
 swfdec_player_dispose (GObject *object)
 {
-  GList *walk;
   SwfdecPlayer *player = SWFDEC_PLAYER (object);
 
   swfdec_player_stop_all_sounds (player);
@@ -337,28 +329,16 @@ swfdec_player_dispose (GObject *object)
   g_list_foreach (player->roots, (GFunc) swfdec_movie_destroy, NULL);
   g_list_free (player->roots);
 
-  if (player->rate) {
-    swfdec_player_remove_timeout (player, &player->iterate_timeout);
-  }
-  walk = player->timeouts;
-  while (walk) {
-    SwfdecTimeout *timeout = walk->data;
-    walk = walk->next;
-    if (timeout->free) {
-      /* all the others must remove themselves */
-      timeout->free (timeout);
-      swfdec_player_remove_timeout (player, timeout);
-    }
-  }
   swfdec_js_finish_player (player);
 
   g_assert (swfdec_ring_buffer_pop (player->actions) == NULL);
   swfdec_ring_buffer_free (player->actions);
   g_assert (player->movies == NULL);
   g_assert (player->audio == NULL);
+  if (player->rate) {
+    swfdec_player_remove_timeout (player, &player->iterate_timeout);
+  }
   g_assert (player->timeouts == NULL);
-  g_list_free (player->timeouts);
-  player->timeouts = NULL;
   swfdec_cache_unref (player->cache);
 
   G_OBJECT_CLASS (swfdec_player_parent_class)->dispose (object);
diff-tree 77b34b229da25f92968a27d4ed759f154b6519b2 (from ea81d2b805d5db2b7506c1c817efb5f9b8041b3c)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 18:44:12 2007 +0100

    arguments.toString() returns the empty string

diff --git a/libswfdec/js/jsobj.c b/libswfdec/js/jsobj.c
index 396c724..860e38c 100644
--- a/libswfdec/js/jsobj.c
+++ b/libswfdec/js/jsobj.c
@@ -913,13 +913,21 @@ js_obj_toString(JSContext *cx, JSObject 
     size_t nchars;
     const char *clazz, *prefix;
     JSString *str;
+    JSClass *clasp;
 
 #if JS_HAS_INITIALIZERS
     if (cx->version == JSVERSION_1_2)
         return js_obj_toSource(cx, obj, argc, argv, rval);
 #endif
 
-    clazz = OBJ_GET_CLASS(cx, obj)->name;
+    clasp = OBJ_GET_CLASS(cx, obj);
+    clazz = clasp->name;
+    /* special case in here (woohoo) */
+    if (clasp == &js_ArgumentsClass) {
+      *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
+      return JS_TRUE;
+    }
+
     nchars = 9 + strlen(clazz);         /* 9 for "[object ]" */
     chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar));
     if (!chars)
diff-tree ea81d2b805d5db2b7506c1c817efb5f9b8041b3c (from 0ff56e6acbc042b3b914242565414a349796ca6f)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 17:38:24 2007 +0100

    shuffle disposing around again so timeouts get properly removed

diff --git a/libswfdec/swfdec_player.c b/libswfdec/swfdec_player.c
index fa5633a..0b52aeb 100644
--- a/libswfdec/swfdec_player.c
+++ b/libswfdec/swfdec_player.c
@@ -337,20 +337,26 @@ swfdec_player_dispose (GObject *object)
   g_list_foreach (player->roots, (GFunc) swfdec_movie_destroy, NULL);
   g_list_free (player->roots);
 
+  if (player->rate) {
+    swfdec_player_remove_timeout (player, &player->iterate_timeout);
+  }
+  walk = player->timeouts;
+  while (walk) {
+    SwfdecTimeout *timeout = walk->data;
+    walk = walk->next;
+    if (timeout->free) {
+      /* all the others must remove themselves */
+      timeout->free (timeout);
+      swfdec_player_remove_timeout (player, timeout);
+    }
+  }
   swfdec_js_finish_player (player);
 
   g_assert (swfdec_ring_buffer_pop (player->actions) == NULL);
   swfdec_ring_buffer_free (player->actions);
   g_assert (player->movies == NULL);
   g_assert (player->audio == NULL);
-  if (player->rate) {
-    swfdec_player_remove_timeout (player, &player->iterate_timeout);
-  }
-  for (walk = player->timeouts; walk; walk = walk->next) {
-    SwfdecTimeout *timeout = walk->data;
-    g_assert (timeout->free); /* all the others must have removed themselves above */
-    timeout->free (timeout);
-  }
+  g_assert (player->timeouts == NULL);
   g_list_free (player->timeouts);
   player->timeouts = NULL;
   swfdec_cache_unref (player->cache);
diff-tree 0ff56e6acbc042b3b914242565414a349796ca6f (from a1ad80fa10c826ede2378b0c61983daf8ed8a223)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 17:37:57 2007 +0100

    register variables are 1-indexed
    
    We keep a register 0 around anyway to ease actions accessing registers, since
    those commands are 0-indexed.

diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index cebac2f..d46687f 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1452,11 +1452,11 @@ swfdec_action_do_define_function (JSCont
   if (fun == NULL)
     return JS_FALSE;
   if (v2) {
-    fun->nvars = swfdec_bits_get_u8 (&bits);
+    fun->nvars = swfdec_bits_get_u8 (&bits) + 1;
     flags = swfdec_bits_get_u16 (&bits);
     preloads = g_new0 (guint8, n_args);
   } else {
-    fun->nvars = 4;
+    fun->nvars = 5;
   }
   for (i = 0; i < n_args; i++) {
     JSAtom *atom;
@@ -2376,7 +2376,7 @@ swfdec_script_interpret (SwfdecScript *s
     }
   }
   if (script->flags) {
-    guint preload_reg = 0;
+    guint preload_reg = 1;
     SwfdecPlayer *player = JS_GetContextPrivate (cx);
     if (script->flags & SWFDEC_SCRIPT_PRELOAD_THIS)
       fp->vars[preload_reg++] = OBJECT_TO_JSVAL (fp->thisp);
diff-tree a1ad80fa10c826ede2378b0c61983daf8ed8a223 (from 20654e6ae4379f8c7fbf3508e8990292d83a94df)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 15:41:25 2007 +0100

    allow timeouts to be destroyed by a destroy function
    
    This is in preparation for setInterval/clearInterval support

diff --git a/libswfdec/swfdec_player.c b/libswfdec/swfdec_player.c
index a1b9660..fa5633a 100644
--- a/libswfdec/swfdec_player.c
+++ b/libswfdec/swfdec_player.c
@@ -329,6 +329,7 @@ swfdec_player_set_property (GObject *obj
 static void
 swfdec_player_dispose (GObject *object)
 {
+  GList *walk;
   SwfdecPlayer *player = SWFDEC_PLAYER (object);
 
   swfdec_player_stop_all_sounds (player);
@@ -345,7 +346,13 @@ swfdec_player_dispose (GObject *object)
   if (player->rate) {
     swfdec_player_remove_timeout (player, &player->iterate_timeout);
   }
-  g_assert (player->timeouts == NULL);
+  for (walk = player->timeouts; walk; walk = walk->next) {
+    SwfdecTimeout *timeout = walk->data;
+    g_assert (timeout->free); /* all the others must have removed themselves above */
+    timeout->free (timeout);
+  }
+  g_list_free (player->timeouts);
+  player->timeouts = NULL;
   swfdec_cache_unref (player->cache);
 
   G_OBJECT_CLASS (swfdec_player_parent_class)->dispose (object);
diff --git a/libswfdec/swfdec_player_internal.h b/libswfdec/swfdec_player_internal.h
index be548b4..7aa499d 100644
--- a/libswfdec/swfdec_player_internal.h
+++ b/libswfdec/swfdec_player_internal.h
@@ -34,6 +34,7 @@ typedef struct _SwfdecTimeout SwfdecTime
 struct _SwfdecTimeout {
   SwfdecTick		timestamp;		/* timestamp at which this thing is supposed to trigger */
   void			(* callback)		(SwfdecTimeout *advance);
+  void			(* free)		(SwfdecTimeout *advance);
 };
 
 struct _SwfdecPlayer
diff-tree 20654e6ae4379f8c7fbf3508e8990292d83a94df (from 163927d06c825430b89ed775925a6b9eb7578f22)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 13:38:09 2007 +0100

    various small fixes
    
    - script functions are heavyweight (otherwise they get inlined by jsinterp.c)
    - implement suppression of arguments property and suppress by default
      This way scripts get no argumens object when executed
    - initialize some variables to NULL in swfdec_script_execute that get later
      set when initializing the call object

diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 60b58f1..cebac2f 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1442,10 +1442,12 @@ swfdec_action_do_define_function (JSCont
   n_args = swfdec_bits_get_u16 (&bits);
   if (*function_name == '\0') {
     /* anonymous function */
-    fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA, cx->fp->thisp, NULL);
+    fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA | JSFUN_HEAVYWEIGHT,
+	cx->fp->thisp, NULL);
   } else {
     /* named function */
-    fun = JS_NewFunction (cx, NULL, n_args, 0, cx->fp->thisp, function_name);
+    fun = JS_NewFunction (cx, NULL, n_args, JSFUN_HEAVYWEIGHT, 
+	cx->fp->thisp, function_name);
   }
   if (fun == NULL)
     return JS_FALSE;
@@ -2284,6 +2286,9 @@ swfdec_script_new (SwfdecBits *bits, con
   script->refcount = 1;
   script->name = g_strdup (name ? name : "Unnamed script");
   script->version = version;
+  /* These flags are the default arguments used by scripts read from a file.
+   * DefineFunction and friends override this */
+  script->flags = SWFDEC_SCRIPT_SUPPRESS_ARGS;
 
   if (!swfdec_script_foreach_internal (bits, validate_action, script)) {
     /* assign a random buffer here so we have something to unref */
@@ -2375,8 +2380,16 @@ swfdec_script_interpret (SwfdecScript *s
     SwfdecPlayer *player = JS_GetContextPrivate (cx);
     if (script->flags & SWFDEC_SCRIPT_PRELOAD_THIS)
       fp->vars[preload_reg++] = OBJECT_TO_JSVAL (fp->thisp);
-    if (script->flags & SWFDEC_SCRIPT_PRELOAD_ARGS)
-  
+    if (script->flags & SWFDEC_SCRIPT_PRELOAD_ARGS) {
+      if (!JS_GetProperty (cx, fp->scopeChain, "arguments", &fp->vars[preload_reg++])) {
+	ok = JS_FALSE;
+	goto out;
+      }
+    }
+    if (script->flags & SWFDEC_SCRIPT_SUPPRESS_ARGS) {
+      /* FIXME: keep in sync with jsfun.c */
+      fp->flags |= JS_BIT (JSFRAME_OVERRIDE_SHIFT);
+    }
     if (script->flags & SWFDEC_SCRIPT_PRELOAD_SUPER ||
 	script->flags & SWFDEC_SCRIPT_PRELOAD_ROOT ||
 	script->flags & SWFDEC_SCRIPT_PRELOAD_PARENT) {
@@ -2582,7 +2595,7 @@ swfdec_script_execute (SwfdecScript *scr
 
   frame.callobj = frame.argsobj = NULL;
   frame.script = NULL;
-  frame.varobj = obj;
+  frame.varobj = NULL;
   frame.fun = swfdec_script_ensure_function (script, scriptable);
   frame.swf = script;
   frame.constant_pool = NULL;
@@ -2593,7 +2606,7 @@ swfdec_script_execute (SwfdecScript *scr
   frame.sharpArray = NULL;
   frame.rval = JSVAL_VOID;
   frame.down = NULL;
-  frame.scopeChain = obj;
+  frame.scopeChain = NULL;
   frame.pc = NULL;
   frame.sp = oldfp ? oldfp->sp : NULL;
   frame.spbase = NULL;
@@ -2630,6 +2643,11 @@ swfdec_script_execute (SwfdecScript *scr
   if (frame.constant_pool)
     swfdec_constant_pool_free (frame.constant_pool);
 
+  if (frame.callobj)
+    ok &= js_PutCallObject(cx, &frame);
+  if (frame.argsobj)
+    ok &= js_PutArgsObject(cx, &frame);
+
   cx->fp = oldfp;
   if (oldfp) {
     g_assert (cx->dormantFrameChain == oldfp);
diff-tree 163927d06c825430b89ed775925a6b9eb7578f22 (from bdb4e1d3d5946d82bd320c8a6b8090de02547aa8)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 13:35:44 2007 +0100

    Do not lookup flags from bytecode when using Flash bytecodes

diff --git a/libswfdec/js/jsobj.c b/libswfdec/js/jsobj.c
index 112bdc8..396c724 100644
--- a/libswfdec/js/jsobj.c
+++ b/libswfdec/js/jsobj.c
@@ -2469,7 +2469,7 @@ js_LookupPropertyWithFlags(JSContext *cx
 
                 if (clasp->flags & JSCLASS_NEW_RESOLVE) {
                     newresolve = (JSNewResolveOp)resolve;
-                    if (cx->fp && (pc = cx->fp->pc)) {
+                    if (cx->fp && cx->fp->script && (pc = cx->fp->pc)) {
                         cs = &js_CodeSpec[*pc];
                         format = cs->format;
                         if ((format & JOF_MODEMASK) != JOF_NAME)
diff-tree bdb4e1d3d5946d82bd320c8a6b8090de02547aa8 (from 010c30904ac1e78dbbd34fc865a537b506b223b1)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 11:04:22 2007 +0100

    named functions belong to this, not to the scope chain
    
    fixes function2.swf test

diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index d923039..60b58f1 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1530,7 +1530,7 @@ swfdec_action_do_define_function (JSCont
     *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object);
   } else {
     jsval val = OBJECT_TO_JSVAL (fun->object);
-    if (!JS_SetProperty (cx, OBJ_THIS_OBJECT (cx, cx->fp->scopeChain), function_name, &val))
+    if (!JS_SetProperty (cx, cx->fp->thisp, function_name, &val))
       return JS_FALSE;
   }
 
diff-tree 010c30904ac1e78dbbd34fc865a537b506b223b1 (from 23429b410bd475e0bc85db66160d04b2a4c61911)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 10:46:12 2007 +0100

    make sure we really interrupt when breakpoints are set
    
    we're not having a special breakpoint at index 0 anymore, so don't index from 1

diff --git a/libswfdec/swfdec_debugger.c b/libswfdec/swfdec_debugger.c
index 9a255b8..7f3546d 100644
--- a/libswfdec/swfdec_debugger.c
+++ b/libswfdec/swfdec_debugger.c
@@ -253,7 +253,7 @@ swfdec_debugger_update_interrupting (Swf
   guint i;
   gboolean should_interrupt = debugger->stepping;
 
-  for (i = 1; i < debugger->breakpoints->len && !should_interrupt; i++) {
+  for (i = 0; i < debugger->breakpoints->len && !should_interrupt; i++) {
     Breakpoint *br = &g_array_index (debugger->breakpoints, Breakpoint, i);
 
     if (br->script) {
@@ -280,8 +280,9 @@ swfdec_debugger_set_breakpoint (SwfdecDe
   g_return_val_if_fail (script != NULL, 0);
   g_return_val_if_fail (line < script->n_commands, 0);
 
-  if (debugger->breakpoints == NULL)
+  if (debugger->breakpoints == NULL) {
     debugger->breakpoints = g_array_new (FALSE, FALSE, sizeof (Breakpoint));
+  }
   if (script->commands[line].breakpoint != 0)
     return script->commands[line].breakpoint;
 
diff-tree 23429b410bd475e0bc85db66160d04b2a4c61911 (from c13c11c4f1bb89da4ff0ab669868a896859b6d51)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 10:44:58 2007 +0100

    set buffer to NULL if not used, so we don't unref it later

diff --git a/libswfdec/swfdec_tag.c b/libswfdec/swfdec_tag.c
index 97a1e4d..9fd2491 100644
--- a/libswfdec/swfdec_tag.c
+++ b/libswfdec/swfdec_tag.c
@@ -225,6 +225,7 @@ tag_func_define_sprite (SwfdecSwfDecoder
         swfdec_swf_decoder_get_tag_name (tag), tag_len);
 
     if (tag_len == 0) {
+      buffer = NULL;
       swfdec_bits_init_data (&s->b, NULL, 0);
     } else {
       buffer = swfdec_bits_get_buffer (&parse, tag_len);
diff-tree c13c11c4f1bb89da4ff0ab669868a896859b6d51 (from fe60df1a5559878b417a19a4c25355b6b996c56c)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 09:33:14 2007 +0100

    test that calling an undefined function does not abort execution

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 294ae51..73bded0 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -48,6 +48,8 @@ EXTRA_DIST = \
 	function1.swf.trace \
 	function2.swf \
 	function2.swf.trace \
+	function-undefined.swf \
+	function-undefined.swf.trace \
 	goto1.swf \
 	goto1.swf.trace \
 	goto2.swf \
diff --git a/test/trace/function-undefined.swf b/test/trace/function-undefined.swf
new file mode 100755
index 0000000..11484ca
Binary files /dev/null and b/test/trace/function-undefined.swf differ
diff --git a/test/trace/function-undefined.swf.trace b/test/trace/function-undefined.swf.trace
new file mode 100755
index 0000000..742b9e5
--- /dev/null
+++ b/test/trace/function-undefined.swf.trace
@@ -0,0 +1,2 @@
+Test that calling undefined functions doesn't abort
+didn't abort
diff-tree fe60df1a5559878b417a19a4c25355b6b996c56c (from 68420cdc4618b5cb27669920bdef80f63f75f4e8)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 19 08:16:40 2007 +0100

    warn if a function does not exist, so it's easy to see what to implement

diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 6972c81..d923039 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -639,6 +639,10 @@ swfdec_action_call_function (JSContext *
     return JS_FALSE;
   if (!JS_GetProperty (cx, obj, s, &fun))
     return JS_FALSE;
+  if (!JSVAL_IS_OBJECT (fun)) {
+    SWFDEC_WARNING ("%s:%s is not a function",
+	JS_GetClass (obj)->name, s);
+  }
   fp->sp[-1] = fun;
   fp->sp[-2] = OBJECT_TO_JSVAL (obj);
   swfdec_action_call (cx, n_args, 0);
diff-tree 68420cdc4618b5cb27669920bdef80f63f75f4e8 (from 52e6b97641109e79877c007d6da16f7e5d5271b1)
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Feb 17 22:06:14 2007 +0100

    only update the script if the script really changed
    
    big performance boost

diff --git a/player/swfdec_debug_script.c b/player/swfdec_debug_script.c
index 83e61c9..ccf6a3b 100644
--- a/player/swfdec_debug_script.c
+++ b/player/swfdec_debug_script.c
@@ -205,6 +205,8 @@ swfdec_debug_script_set_script (SwfdecDe
 
   if (debug->debugger == NULL)
     return;
+  if (debug->script == dscript)
+    return;
   debug->script = dscript;
   if (dscript) {
     swfdec_debug_script_set_model (debug);
diff-tree 52e6b97641109e79877c007d6da16f7e5d5271b1 (from 7bd0f8a278aeb516f76ecdfb6297debd6fb736ab)
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Feb 17 20:19:24 2007 +0100

    check the parent of root really is undefined

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index f1755ee..294ae51 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -88,6 +88,8 @@ EXTRA_DIST = \
 	object-math-7.swf.trace \
 	order.swf \
 	order.swf.trace \
+	parent-root.swf \
+	parent-root.swf.trace \
 	rotation-5.swf \
 	rotation-5.swf.trace \
 	scope.swf \
diff --git a/test/trace/parent-root.swf b/test/trace/parent-root.swf
new file mode 100755
index 0000000..a8eb741
Binary files /dev/null and b/test/trace/parent-root.swf differ
diff --git a/test/trace/parent-root.swf.trace b/test/trace/parent-root.swf.trace
new file mode 100755
index 0000000..4625226
--- /dev/null
+++ b/test/trace/parent-root.swf.trace
@@ -0,0 +1,2 @@
+The parent of root is:
+undefined
diff-tree 7bd0f8a278aeb516f76ecdfb6297debd6fb736ab (from 4600fb2de56a5b49aa2c4cf8d3d67d2811f8f46a)
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Feb 17 20:18:53 2007 +0100

    the parent of root is undefined

diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c
index dde352d..5b730b3 100644
--- a/libswfdec/swfdec_js_movie.c
+++ b/libswfdec/swfdec_js_movie.c
@@ -979,14 +979,16 @@ mc_parent (JSContext *cx, JSObject *obj,
   g_assert (movie);
 
   /* FIXME: what do we do if we're the root movie? */
-  if (movie->parent)
+  if (movie->parent) {
     movie = movie->parent;
 
-  jsobj = swfdec_scriptable_get_object (SWFDEC_SCRIPTABLE (movie));
-  if (jsobj == NULL)
-    return JS_FALSE;
-  
-  *vp = OBJECT_TO_JSVAL (jsobj);
+    jsobj = swfdec_scriptable_get_object (SWFDEC_SCRIPTABLE (movie));
+    if (jsobj == NULL)
+      return JS_FALSE;
+    
+    *vp = OBJECT_TO_JSVAL (jsobj);
+  }
+  /* else return JSVAL_VOID */
 
   return JS_TRUE;
 }
diff-tree 4600fb2de56a5b49aa2c4cf8d3d67d2811f8f46a (from abee9a29d76d305e67af6632dedc3b66c4e6827c)
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Feb 17 19:53:40 2007 +0100

    make all scripts have a call object
    
    This is required to be able to handle DefineLocal.
    It will definitely break more functions than I've fixed here, so if you find
    one that still assumes fp->scopeChain is the movie object, change it to use
    fp->thisp.
    Now all scripts have their own function, and they can access it via script->fun.
    If the function gets GC'ed, it'll unset it again.

diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c
index a085673..a6ae7fc 100644
--- a/libswfdec/js/jsfun.c
+++ b/libswfdec/js/jsfun.c
@@ -1042,6 +1042,9 @@ fun_convert(JSContext *cx, JSObject *obj
     }
 }
 
+struct _SwfdecScript {
+  JSFunction *		fun;
+};
 extern void swfdec_script_unref (void *script);
 static void
 fun_finalize(JSContext *cx, JSObject *obj)
@@ -1059,8 +1062,10 @@ fun_finalize(JSContext *cx, JSObject *ob
         return;
     if (fun->script)
         js_DestroyScript(cx, fun->script);
-    if (fun->swf)
+    if (fun->swf) {
 	swfdec_script_unref (fun->swf);
+	((struct _SwfdecScript *) fun->swf)->fun = NULL;
+    }
     JS_free(cx, fun);
 }
 
diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c
index 4c14100..481ec48 100644
--- a/libswfdec/swfdec_js.c
+++ b/libswfdec/swfdec_js.c
@@ -334,7 +334,7 @@ swfdec_js_eval_set_property (JSContext *
   if (obj == NULL) {
     if (cx->fp == NULL || cx->fp->scopeChain == NULL)
       return JS_FALSE;
-    obj = cx->fp->scopeChain;
+    obj = JS_GetParent (cx, cx->fp->scopeChain);
   }
   return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret);
 }
@@ -383,8 +383,8 @@ swfdec_js_eval_internal (JSContext *cx, 
   if (obj == NULL) {
     if (cx->fp == NULL)
       goto out;
-    g_assert (cx->fp->scopeChain);
-    cur = OBJECT_TO_JSVAL (OBJ_THIS_OBJECT (cx, cx->fp->scopeChain));
+    g_assert (cx->fp->thisp);
+    cur = OBJECT_TO_JSVAL (cx->fp->thisp);
   }
 
 finish:
diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c
index 10fde07..dde352d 100644
--- a/libswfdec/swfdec_js_movie.c
+++ b/libswfdec/swfdec_js_movie.c
@@ -941,6 +941,35 @@ mc_rotation_set (JSContext *cx, JSObject
 }
 
 static JSBool
+mc_xmouse_get (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+  double x, y;
+  SwfdecMovie *movie;
+
+  movie = JS_GetPrivate (cx, obj);
+  g_assert (movie);
+
+  swfdec_movie_get_mouse (movie, &x, &y);
+  x = rint (x * SWFDEC_TWIPS_SCALE_FACTOR) / SWFDEC_TWIPS_SCALE_FACTOR;
+  return JS_NewNumberValue (cx, x, vp);
+}
+
+static JSBool
+mc_ymouse_get (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+  double x, y;
+  SwfdecMovie *movie;
+
+  movie = JS_GetPrivate (cx, obj);
+  g_assert (movie);
+
+  swfdec_movie_get_mouse (movie, &x, &y);
+  y = rint (y * SWFDEC_TWIPS_SCALE_FACTOR) / SWFDEC_TWIPS_SCALE_FACTOR;
+  return JS_NewNumberValue (cx, y, vp);
+}
+
+/* FIXME: what do we do if we're the root movie? */
+static JSBool
 mc_parent (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
   SwfdecMovie *movie;
@@ -1040,10 +1069,10 @@ static JSPropertySpec movieclip_props[] 
   {"_focusrect",    -1,		MC_PROP_ATTRS,			  not_reached,	    not_reached },
   {"_soundbuftime", -1,		MC_PROP_ATTRS,			  not_reached,	    not_reached },
   {"_quality",	    -1,		MC_PROP_ATTRS,			  not_reached,	    not_reached },
-  {"_xmouse",	    -1,		MC_PROP_ATTRS,			  not_reached,	    not_reached },
-  {"_ymouse",	    -1,		MC_PROP_ATTRS,			  not_reached,	    not_reached },
-  {"_parent",	    -1,	      	MC_PROP_ATTRS | JSPROP_READONLY,  mc_parent,	    NULL},
-  {"_root",	    -1,	      	MC_PROP_ATTRS | JSPROP_READONLY,  mc_root,	    NULL},
+  {"_xmouse",	    -1,		MC_PROP_ATTRS | JSPROP_READONLY,  mc_xmouse_get,    NULL },
+  {"_ymouse",	    -1,		MC_PROP_ATTRS | JSPROP_READONLY,  mc_ymouse_get,    NULL },
+  {"_parent",	    -1,	      	MC_PROP_ATTRS | JSPROP_READONLY,  mc_parent,	    NULL },
+  {"_root",	    -1,	      	MC_PROP_ATTRS | JSPROP_READONLY,  mc_root,	    NULL },
   {NULL}
 };
 
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 1439882..6972c81 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -137,8 +137,7 @@ swfdec_action_has_register (JSContext *c
 static SwfdecMovie *
 swfdec_action_get_target (JSContext *cx)
 {
-  JSObject *object = cx->fp->scopeChain;
-  object = OBJ_THIS_OBJECT (cx, object);
+  JSObject *object = cx->fp->thisp;
   return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (object), SWFDEC_TYPE_MOVIE);
 }
 
@@ -1638,10 +1637,7 @@ swfdec_action_define_local (JSContext *c
 {
   const char *name;
 
-  if (cx->fp->callobj == NULL) {
-    SWFDEC_ERROR ("FIXME: no local scope");
-    return JS_FALSE;
-  }
+  g_assert (cx->fp->callobj != NULL);
   name = swfdec_js_to_string (cx, cx->fp->sp[-2]);
   if (name == NULL)
     return JS_FALSE;
@@ -1657,10 +1653,7 @@ swfdec_action_define_local2 (JSContext *
   const char *name;
   jsval val = JSVAL_VOID;
 
-  if (cx->fp->callobj == NULL) {
-    SWFDEC_ERROR ("FIXME: no local scope");
-    return JS_FALSE;
-  }
+  g_assert (cx->fp->callobj != NULL);
   name = swfdec_js_to_string (cx, cx->fp->sp[-1]);
   if (name == NULL)
     return JS_FALSE;
@@ -2549,6 +2542,22 @@ internal_error:
   goto no_catch;
 }
 
+static JSFunction *
+swfdec_script_ensure_function (SwfdecScript *script, SwfdecScriptable *scriptable)
+{
+  JSContext *cx = scriptable->jscx;
+  JSObject *parent;
+
+  if (script->fun)
+    return script->fun;
+  parent = swfdec_scriptable_get_object (scriptable);
+  script->fun = JS_NewFunction (cx, NULL, 0, JSFUN_LAMBDA, parent, NULL);
+  script->fun->swf = script;
+  script->fun->nvars = 4;
+  swfdec_script_ref (script);
+  return script->fun;
+}
+
 jsval
 swfdec_script_execute (SwfdecScript *script, SwfdecScriptable *scriptable)
 {
@@ -2570,7 +2579,7 @@ swfdec_script_execute (SwfdecScript *scr
   frame.callobj = frame.argsobj = NULL;
   frame.script = NULL;
   frame.varobj = obj;
-  frame.fun = NULL;
+  frame.fun = swfdec_script_ensure_function (script, scriptable);
   frame.swf = script;
   frame.constant_pool = NULL;
   frame.thisp = obj;
@@ -2596,13 +2605,15 @@ swfdec_script_execute (SwfdecScript *scr
     return JS_FALSE;
   }
   frame.vars[0] = frame.vars[1] = frame.vars[2] = frame.vars[3] = JSVAL_VOID;
+  /* create a call object */
+  if (!js_GetCallObject(cx, &frame, obj))
+    return JS_FALSE;
 
   if (oldfp) {
     g_assert (!oldfp->dormantNext);
     oldfp->dormantNext = cx->dormantFrameChain;
     cx->dormantFrameChain = oldfp;
   }
-
   cx->fp = &frame;
 
   /*
diff --git a/libswfdec/swfdec_script.h b/libswfdec/swfdec_script.h
index 82d2169..8af5755 100644
--- a/libswfdec/swfdec_script.h
+++ b/libswfdec/swfdec_script.h
@@ -46,6 +46,8 @@ typedef gboolean (* SwfdecScriptForeachF
 
 /* FIXME: May want to typedef to SwfdecBuffer directly */
 struct _SwfdecScript {
+  /* must be first arg */
+  JSFunction *		fun;			/* function script belongs to or NULL */
   SwfdecBuffer *	buffer;			/* buffer holding the script */
   unsigned int	  	refcount;		/* reference count */
   char *		name;			/* name identifying this script */
diff-tree abee9a29d76d305e67af6632dedc3b66c4e6827c (from 20b8eddca6677d1c69f541d058fce59031487450)
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Feb 17 19:39:16 2007 +0100

    document swfdec_movie_get_mouse

diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c
index 3ab9c88..cbb787c 100644
--- a/libswfdec/swfdec_movie.c
+++ b/libswfdec/swfdec_movie.c
@@ -401,6 +401,14 @@ swfdec_movie_global_to_local (SwfdecMovi
   cairo_matrix_transform_point (&movie->inverse_matrix, x, y);
 }
 
+/**
+ * swfdec_movie_get_mouse:
+ * @movie: a #SwfdecMovie
+ * @x: pointer to hold result of X coordinate
+ * @y: pointer to hold result of y coordinate
+ *
+ * Gets the mouse coordinates in the coordinate space of @movie.
+ **/
 void
 swfdec_movie_get_mouse (SwfdecMovie *movie, double *x, double *y)
 {


More information about the Swfdec mailing list