[Swfdec] 6 commits - libswfdec/swfdec_as_strings.c libswfdec/swfdec_movie.c libswfdec/swfdec_movie.h libswfdec/swfdec_text_field.c libswfdec/swfdec_text_field.h libswfdec/swfdec_text_field_movie_as.c libswfdec/swfdec_text_field_movie.c libswfdec/swfdec_text_field_movie.h

Pekka Lampila medar at kemper.freedesktop.org
Wed Oct 17 04:47:09 PDT 2007


 libswfdec/swfdec_as_strings.c          |    4 
 libswfdec/swfdec_movie.c               |   76 +++++
 libswfdec/swfdec_movie.h               |   19 +
 libswfdec/swfdec_text_field.c          |   23 +
 libswfdec/swfdec_text_field.h          |    2 
 libswfdec/swfdec_text_field_movie.c    |  420 ++++++++++++++++++++++++++++---
 libswfdec/swfdec_text_field_movie.h    |    5 
 libswfdec/swfdec_text_field_movie_as.c |  434 +++++++++++----------------------
 8 files changed, 641 insertions(+), 342 deletions(-)

New commits:
commit 429ccc9fb71cb675129bd008f0523b5621ff428c
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Oct 17 14:46:53 2007 +0300

    Implement TextField's variable property
    
    Previously it was only supported from tag and was only updated between frames
    Currently the lookup of the variable is not implemented properly, so only
    properties of the parent movie will work at the moment

diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c
index 3d8bade..a5ffa00 100644
--- a/libswfdec/swfdec_movie.c
+++ b/libswfdec/swfdec_movie.c
@@ -947,12 +947,18 @@ swfdec_movie_mark (SwfdecAsObject *object)
 {
   SwfdecMovie *movie = SWFDEC_MOVIE (object);
   GList *walk;
+  GSList *iter;
 
   swfdec_as_string_mark (movie->original_name);
   swfdec_as_string_mark (movie->name);
   for (walk = movie->list; walk; walk = walk->next) {
     swfdec_as_object_mark (walk->data);
   }
+  for (iter = movie->variable_listeners; iter != NULL; iter = iter->next) {
+    SwfdecMovieVariableListener *listener = iter->data;
+    swfdec_as_object_mark (listener->object);
+    swfdec_as_string_mark (listener->name);
+  }
 
   SWFDEC_AS_OBJECT_CLASS (swfdec_movie_parent_class)->mark (object);
 }
@@ -1046,6 +1052,72 @@ swfdec_movie_get_variable (SwfdecAsObject *object, SwfdecAsObject *orig,
   return FALSE;
 }
 
+void
+swfdec_movie_add_variable_listener (SwfdecMovie *movie, SwfdecAsObject *object,
+    const char *name, const SwfdecMovieVariableListenerFunction function)
+{
+  SwfdecMovieVariableListener *listener;
+  GSList *iter;
+
+  for (iter = movie->variable_listeners; iter != NULL; iter = iter->next) {
+    listener = iter->data;
+
+    if (listener->object == object && listener->name == name &&
+	listener->function == function)
+      break;
+  }
+  if (iter != NULL)
+    return;
+
+  listener = g_new0 (SwfdecMovieVariableListener, 1);
+  listener->object = object;
+  listener->name = name;
+  listener->function = function;
+
+  movie->variable_listeners = g_slist_prepend (movie->variable_listeners,
+      listener);
+}
+
+void
+swfdec_movie_remove_variable_listener (SwfdecMovie *movie,
+    SwfdecAsObject *object, const char *name,
+    const SwfdecMovieVariableListenerFunction function)
+{
+  GSList *iter;
+
+  for (iter = movie->variable_listeners; iter != NULL; iter = iter->next) {
+    SwfdecMovieVariableListener *listener = iter->data;
+
+    if (listener->object == object && listener->name == name &&
+	listener->function == function)
+      break;
+  }
+  if (iter == NULL)
+    return;
+
+  movie->variable_listeners =
+    g_slist_remove (movie->variable_listeners, iter->data);
+  g_free (iter->data);
+}
+
+static void
+swfdec_movie_call_variable_listeners (SwfdecMovie *movie, const char *name,
+    const SwfdecAsValue *val)
+{
+  GSList *iter;
+
+  for (iter = movie->variable_listeners; iter != NULL; iter = iter->next) {
+    SwfdecMovieVariableListener *listener = iter->data;
+
+    if (listener->name != name &&
+	(SWFDEC_AS_OBJECT (movie)->context->version >= 7 ||
+	 !swfdec_str_case_equal (listener->name, name)))
+      continue;
+
+    listener->function (listener->object, name, val);
+  }
+}
+
 static void
 swfdec_movie_set_variable (SwfdecAsObject *object, const char *variable, 
     const SwfdecAsValue *val, guint flags)
@@ -1054,8 +1126,12 @@ swfdec_movie_set_variable (SwfdecAsObject *object, const char *variable,
 
   if (movie->state == SWFDEC_MOVIE_STATE_DESTROYED)
     return;
+
   if (swfdec_movie_set_asprop (movie, variable, val))
     return;
+
+  swfdec_movie_call_variable_listeners (movie, variable, val);
+
   SWFDEC_AS_OBJECT_CLASS (swfdec_movie_parent_class)->set (object, variable, val, flags);
 }
 
diff --git a/libswfdec/swfdec_movie.h b/libswfdec/swfdec_movie.h
index 3b41d2f..ab2ad32 100644
--- a/libswfdec/swfdec_movie.h
+++ b/libswfdec/swfdec_movie.h
@@ -84,6 +84,15 @@ typedef enum {
   SWFDEC_MOVIE_INVALID_MATRIX		/* matrix is invalid, recalculate */
 } SwfdecMovieCacheState;
 
+typedef void (*SwfdecMovieVariableListenerFunction) (SwfdecAsObject *object,
+    const char *name, const SwfdecAsValue *val);
+
+typedef struct {
+  SwfdecAsObject *			object;
+  const char *				name;
+  SwfdecMovieVariableListenerFunction	function;
+} SwfdecMovieVariableListener;
+
 struct _SwfdecMovie {
   SwfdecAsObject	object;
 
@@ -93,6 +102,7 @@ struct _SwfdecMovie {
   int			depth;			/* depth of movie (equals content->depth unless explicitly set) */
   SwfdecMovieCacheState	cache_state;		/* whether we are up to date */
   SwfdecMovieState	state;			/* state the movie is in */
+  GSList		*variable_listeners;	/* textfield's listening to changes in variables - SwfdecMovieVariableListener */
 
   /* static properties (set by PlaceObject tags) */
   const char *		original_name;		/* the original name - GC'd and static */
@@ -260,5 +270,14 @@ gboolean	swfdec_movie_get_asprop		(SwfdecMovie *		movie,
 						 const char *		name,
 						 SwfdecAsValue *	val);
 
+void		swfdec_movie_add_variable_listener (SwfdecMovie *	movie,
+						 SwfdecAsObject *	object,
+						 const char *		name,
+						 const SwfdecMovieVariableListenerFunction	function);
+void		swfdec_movie_remove_variable_listener (SwfdecMovie *	movie,
+						 SwfdecAsObject *	object,
+						 const char *		name,
+						 const SwfdecMovieVariableListenerFunction	function);
+
 G_END_DECLS
 #endif
diff --git a/libswfdec/swfdec_text_field_movie.c b/libswfdec/swfdec_text_field_movie.c
index dc31b4e..e9f7800 100644
--- a/libswfdec/swfdec_text_field_movie.c
+++ b/libswfdec/swfdec_text_field_movie.c
@@ -609,14 +609,9 @@ swfdec_text_field_movie_init_movie (SwfdecMovie *movie)
   }
 
   // variable
-  if (text->text->variable != NULL)
-  {
-    // FIXME: test
-    const char *str;
-    text->variable = swfdec_as_context_get_string (cx, text->text->variable);
-    str = swfdec_text_field_movie_get_variable_text (text);
-    if (str != NULL)
-      swfdec_text_field_movie_set_text (text, str, text->text->html);
+  if (text->text->variable != NULL) {
+    swfdec_text_field_movie_set_listen_variable (text,
+	swfdec_as_context_get_string (cx, text->text->variable));
   }
 }
 
@@ -721,39 +716,92 @@ swfdec_text_field_movie_set_text_format (SwfdecTextFieldMovie *text,
   swfdec_text_field_movie_format_changed (text);
 }
 
+static void
+swfdec_text_field_movie_parse_listen_variable (SwfdecTextFieldMovie *text,
+    const char *variable, SwfdecAsObject **object, const char **name)
+{
+  g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
+  g_return_if_fail (variable != NULL);
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (name != NULL);
+
+  // FIXME: proper variable lookup (have fun)
+  *object = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (text)->parent);
+  *name = variable;
+}
+
 void
-swfdec_text_field_movie_set_variable_text (SwfdecTextFieldMovie *text,
+swfdec_text_field_movie_set_listen_variable_text (SwfdecTextFieldMovie *text,
     const char *value)
 {
-  SwfdecAsObject *parent;
-  SwfdecAsValue val;
+  SwfdecAsObject *object;
+  const char *name;
 
   g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
   g_return_if_fail (text->variable != NULL);
+  g_return_if_fail (value != NULL);
+
+  swfdec_text_field_movie_parse_listen_variable (text, text->variable,
+      &object, &name);
+  if (object != NULL) {
+    SwfdecAsValue val;
+    SWFDEC_AS_VALUE_SET_STRING (&val, value);
+    swfdec_as_object_set_variable (object, name, &val);
+  }
+}
+
+static void
+swfdec_text_field_movie_variable_listener_callback (SwfdecAsObject *object,
+    const char *name, const SwfdecAsValue *val)
+{
+  SwfdecTextFieldMovie *text;
 
-  // FIXME: proper variable lookup
-  parent = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (text)->parent);
+  g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (object));
 
-  SWFDEC_AS_VALUE_SET_STRING (&val, value);
-  swfdec_as_object_set_variable (parent, text->variable, &val);
+  text = SWFDEC_TEXT_FIELD_MOVIE (object);
+  swfdec_text_field_movie_set_text (text,
+      swfdec_as_value_to_string (object->context, val), text->text->html);
 }
 
-const char *
-swfdec_text_field_movie_get_variable_text (SwfdecTextFieldMovie *text)
+void
+swfdec_text_field_movie_set_listen_variable (SwfdecTextFieldMovie *text,
+    const char *value)
 {
-  SwfdecAsObject *parent;
-  SwfdecAsValue val;
+  SwfdecAsObject *object;
+  const char *name;
 
-  g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text), NULL);
-  g_return_val_if_fail (text->variable != NULL, NULL);
+  // FIXME: case-insensitive when v < 7?
+  if (text->variable == value)
+    return;
 
-  // FIXME: proper variable lookup
-  parent = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (text)->parent);
+  if (text->variable != NULL) {
+    swfdec_text_field_movie_parse_listen_variable (text, text->variable,
+	&object, &name);
+    if (object != NULL && SWFDEC_IS_MOVIE (object)) {
+      swfdec_movie_remove_variable_listener (SWFDEC_MOVIE (object),
+	  SWFDEC_AS_OBJECT (text), name,
+	  swfdec_text_field_movie_variable_listener_callback);
+    }
+  }
+
+  text->variable = value;
 
-  if (!swfdec_as_object_get_variable (parent, text->variable, &val))
-    return NULL;
+  if (value != NULL) {
+    SwfdecAsValue val;
 
-  return swfdec_as_value_to_string (parent->context, &val);
+    swfdec_text_field_movie_parse_listen_variable (text, value, &object,
+	&name);
+    if (object != NULL && swfdec_as_object_get_variable (object, name, &val)) {
+      swfdec_text_field_movie_set_text (text,
+	  swfdec_as_value_to_string (SWFDEC_AS_OBJECT (text)->context, &val),
+	  text->text->html);
+    }
+    if (object != NULL && SWFDEC_IS_MOVIE (object)) {
+      swfdec_movie_add_variable_listener (SWFDEC_MOVIE (object),
+	  SWFDEC_AS_OBJECT (text), name,
+	  swfdec_text_field_movie_variable_listener_callback);
+    }
+  }
 }
 
 static const char *
diff --git a/libswfdec/swfdec_text_field_movie.h b/libswfdec/swfdec_text_field_movie.h
index a19fcb9..02b7b73 100644
--- a/libswfdec/swfdec_text_field_movie.h
+++ b/libswfdec/swfdec_text_field_movie.h
@@ -88,10 +88,11 @@ void		swfdec_text_field_movie_set_text_format	(SwfdecTextFieldMovie *	text,
 							 guint			end_index);
 void		swfdec_text_field_movie_set_scroll	(SwfdecTextFieldMovie *	text,
 							 int			value);
-const char *	swfdec_text_field_movie_get_variable_text (SwfdecTextFieldMovie *	text);
-void		swfdec_text_field_movie_set_variable_text (SwfdecTextFieldMovie		*text,
-							 const char *			value);
 const char *	swfdec_text_field_movie_get_html_text	(SwfdecTextFieldMovie *		text);
+void		swfdec_text_field_movie_set_listen_variable (SwfdecTextFieldMovie *	text,
+							 const char *			value);
+void		swfdec_text_field_movie_set_listen_variable_text (SwfdecTextFieldMovie		*text,
+							 const char *			value);
 
 /* implemented in swfdec_text_field_movie_as.c */
 void		swfdec_text_field_movie_init_properties	(SwfdecAsContext *	cx);
diff --git a/libswfdec/swfdec_text_field_movie_as.c b/libswfdec/swfdec_text_field_movie_as.c
index 375f780..e6c4ff5 100644
--- a/libswfdec/swfdec_text_field_movie_as.c
+++ b/libswfdec/swfdec_text_field_movie_as.c
@@ -87,7 +87,7 @@ swfdec_text_field_movie_do_set_text (SwfdecAsContext *cx,
   swfdec_text_field_movie_set_text (text, value, FALSE);
 
   if (text->variable != NULL) {
-    swfdec_text_field_movie_set_variable_text (text,
+    swfdec_text_field_movie_set_listen_variable_text (text,
 	swfdec_text_field_movie_get_html_text (text));
   }
 }
@@ -143,7 +143,7 @@ swfdec_text_field_movie_set_htmlText (SwfdecAsContext *cx,
   swfdec_text_field_movie_set_text (text, value, text->text->html);
 
   if (text->variable != NULL) {
-    swfdec_text_field_movie_set_variable_text (text,
+    swfdec_text_field_movie_set_listen_variable_text (text,
 	swfdec_text_field_movie_get_html_text (text));
   }
 }
@@ -335,7 +335,7 @@ swfdec_text_field_movie_do_set_variable (SwfdecAsContext *cx,
     SwfdecAsValue *ret)
 {
   SwfdecTextFieldMovie *text;
-  const char *value, *str;
+  const char *value;
 
   if (argc > 0)
     swfdec_as_value_to_number (cx, &argv[0]);
@@ -344,12 +344,10 @@ swfdec_text_field_movie_do_set_variable (SwfdecAsContext *cx,
 
   if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
       SWFDEC_AS_VALUE_IS_NULL (&argv[0]) || value == SWFDEC_AS_STR_EMPTY) {
-    text->variable = NULL;
-  } else if (value != text->variable) {
-    text->variable = value;
-    str = swfdec_text_field_movie_get_variable_text (text);
-    swfdec_text_field_movie_set_text (text, str, text->text->html);
+    value = NULL;
   }
+
+  swfdec_text_field_movie_set_listen_variable (text, value);
 }
 
 /*
commit af7a544f53bb873e221e90f582e61d9158e3b316
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon Oct 15 18:54:08 2007 +0300

    Fix an assert when initializing a movie with variable that doesn't exist

diff --git a/libswfdec/swfdec_text_field_movie.c b/libswfdec/swfdec_text_field_movie.c
index 33017e0..dc31b4e 100644
--- a/libswfdec/swfdec_text_field_movie.c
+++ b/libswfdec/swfdec_text_field_movie.c
@@ -615,7 +615,8 @@ swfdec_text_field_movie_init_movie (SwfdecMovie *movie)
     const char *str;
     text->variable = swfdec_as_context_get_string (cx, text->text->variable);
     str = swfdec_text_field_movie_get_variable_text (text);
-    swfdec_text_field_movie_set_text (text, str, text->text->html);
+    if (str != NULL)
+      swfdec_text_field_movie_set_text (text, str, text->text->html);
   }
 }
 
commit 803c524c11bf24f68b1d31788a1c5d9731855ad9
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon Oct 15 18:50:50 2007 +0300

    TextField: Update variable's value even if it hasn't changed when changing text

diff --git a/libswfdec/swfdec_text_field_movie.c b/libswfdec/swfdec_text_field_movie.c
index e6fbaac..33017e0 100644
--- a/libswfdec/swfdec_text_field_movie.c
+++ b/libswfdec/swfdec_text_field_movie.c
@@ -720,7 +720,7 @@ swfdec_text_field_movie_set_text_format (SwfdecTextFieldMovie *text,
   swfdec_text_field_movie_format_changed (text);
 }
 
-static void
+void
 swfdec_text_field_movie_set_variable_text (SwfdecTextFieldMovie *text,
     const char *value)
 {
@@ -1040,7 +1040,6 @@ swfdec_text_field_movie_set_text (SwfdecTextFieldMovie *text, const char *str,
 {
   SwfdecFormatIndex *block;
   GSList *iter;
-  const char *html_text, *variable_text;
 
   g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
   g_return_if_fail (str != NULL);
@@ -1084,13 +1083,5 @@ swfdec_text_field_movie_set_text (SwfdecTextFieldMovie *text, const char *str,
     }
   }
 
-  if (text->variable != NULL) {
-    html_text = swfdec_text_field_movie_get_html_text (text);
-    variable_text = swfdec_text_field_movie_get_variable_text (text);
-
-    if (html_text != variable_text)
-      swfdec_text_field_movie_set_variable_text (text, html_text);
-  }
-
   swfdec_text_field_movie_format_changed (text);
 }
diff --git a/libswfdec/swfdec_text_field_movie.h b/libswfdec/swfdec_text_field_movie.h
index 3c31c8d..a19fcb9 100644
--- a/libswfdec/swfdec_text_field_movie.h
+++ b/libswfdec/swfdec_text_field_movie.h
@@ -89,6 +89,8 @@ void		swfdec_text_field_movie_set_text_format	(SwfdecTextFieldMovie *	text,
 void		swfdec_text_field_movie_set_scroll	(SwfdecTextFieldMovie *	text,
 							 int			value);
 const char *	swfdec_text_field_movie_get_variable_text (SwfdecTextFieldMovie *	text);
+void		swfdec_text_field_movie_set_variable_text (SwfdecTextFieldMovie		*text,
+							 const char *			value);
 const char *	swfdec_text_field_movie_get_html_text	(SwfdecTextFieldMovie *		text);
 
 /* implemented in swfdec_text_field_movie_as.c */
diff --git a/libswfdec/swfdec_text_field_movie_as.c b/libswfdec/swfdec_text_field_movie_as.c
index f579d21..375f780 100644
--- a/libswfdec/swfdec_text_field_movie_as.c
+++ b/libswfdec/swfdec_text_field_movie_as.c
@@ -85,6 +85,11 @@ swfdec_text_field_movie_do_set_text (SwfdecAsContext *cx,
   SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "s", &value);
 
   swfdec_text_field_movie_set_text (text, value, FALSE);
+
+  if (text->variable != NULL) {
+    swfdec_text_field_movie_set_variable_text (text,
+	swfdec_text_field_movie_get_html_text (text));
+  }
 }
 
 static void
@@ -136,6 +141,11 @@ swfdec_text_field_movie_set_htmlText (SwfdecAsContext *cx,
   SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "s", &value);
 
   swfdec_text_field_movie_set_text (text, value, text->text->html);
+
+  if (text->variable != NULL) {
+    swfdec_text_field_movie_set_variable_text (text,
+	swfdec_text_field_movie_get_html_text (text));
+  }
 }
 
 static void
commit 71c83fbeba3f310ec716937c20c99b7b2df3bb20
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon Oct 15 16:31:06 2007 +0300

    Add TextField's variable property
    
    TextField's text is not yet updated when the variable changes
    Currently the variable is not looked up in the right way

diff --git a/libswfdec/swfdec_as_strings.c b/libswfdec/swfdec_as_strings.c
index a47dee8..95f8f2e 100644
--- a/libswfdec/swfdec_as_strings.c
+++ b/libswfdec/swfdec_as_strings.c
@@ -408,5 +408,6 @@ const char swfdec_as_strings[] =
   SWFDEC_AS_CONSTANT_STRING ("maxChars")
   SWFDEC_AS_CONSTANT_STRING ("selectable")
   SWFDEC_AS_CONSTANT_STRING ("password")
+  SWFDEC_AS_CONSTANT_STRING ("variable")
   /* add more here */
 ;
diff --git a/libswfdec/swfdec_text_field.c b/libswfdec/swfdec_text_field.c
index 064dcd0..0db0c37 100644
--- a/libswfdec/swfdec_text_field.c
+++ b/libswfdec/swfdec_text_field.c
@@ -58,12 +58,18 @@ swfdec_text_field_dispose (GObject *object)
 {
   SwfdecTextField *text = SWFDEC_TEXT_FIELD (object);
 
-  g_free (text->text_input);
-  text->text_input = NULL;
-  g_free (text->variable);
-  text->variable = NULL;
-  g_free (text->font);
-  text->font = NULL;
+  if (text->text_input != NULL) {
+    g_free (text->text_input);
+    text->text_input = NULL;
+  }
+  if (text->variable != NULL) {
+    g_free (text->variable);
+    text->variable = NULL;
+  }
+  if (text->font != NULL) {
+    g_free (text->font);
+    text->font = NULL;
+  }
 
   G_OBJECT_CLASS (swfdec_text_field_parent_class)->dispose (object);
 }
diff --git a/libswfdec/swfdec_text_field_movie.c b/libswfdec/swfdec_text_field_movie.c
index e40001f..e6fbaac 100644
--- a/libswfdec/swfdec_text_field_movie.c
+++ b/libswfdec/swfdec_text_field_movie.c
@@ -29,7 +29,7 @@
 #include "swfdec_as_context.h"
 #include "swfdec_as_strings.h"
 #include "swfdec_text_format.h"
-#include "swfdec_font.h"
+#include "swfdec_xml.h"
 #include "swfdec_debug.h"
 #include "swfdec_player_internal.h"
 
@@ -565,37 +565,11 @@ swfdec_text_field_movie_mark (SwfdecAsObject *object)
 }
 
 static void
-swfdec_text_field_movie_iterate (SwfdecMovie *movie)
-{
-  SwfdecTextFieldMovie *text = SWFDEC_TEXT_FIELD_MOVIE (movie);
-  SwfdecAsObject *parent;
-  const char *s;
-  SwfdecAsValue val = { 0, };
-
-  if (text->text->variable == NULL)
-    return;
-
-  parent = SWFDEC_AS_OBJECT (movie->parent);
-  swfdec_as_context_eval (parent->context, parent, text->text->variable, &val);
-  if (SWFDEC_AS_VALUE_IS_UNDEFINED (&val))
-    return;
-
-  s = swfdec_as_value_to_string (parent->context, &val);
-  g_assert (s);
-  if (text->text_input == s)
-    return;
-
-  swfdec_text_field_movie_set_text (text, s, text->text->html);
-}
-
-static void
 swfdec_text_field_movie_init_movie (SwfdecMovie *movie)
 {
   SwfdecTextFieldMovie *text = SWFDEC_TEXT_FIELD_MOVIE (movie);
   SwfdecAsContext *cx;
-  SwfdecAsObject *parent;
   SwfdecAsValue val;
-  const char *s;
 
   cx = SWFDEC_AS_OBJECT (movie)->context;
 
@@ -637,24 +611,11 @@ swfdec_text_field_movie_init_movie (SwfdecMovie *movie)
   // variable
   if (text->text->variable != NULL)
   {
+    // FIXME: test
+    const char *str;
     text->variable = swfdec_as_context_get_string (cx, text->text->variable);
-
-    parent = SWFDEC_AS_OBJECT (movie->parent);
-    swfdec_as_context_eval (parent->context, parent, text->variable, &val);
-    if (!SWFDEC_AS_VALUE_IS_UNDEFINED (&val)) {
-      s = swfdec_as_value_to_string (parent->context, &val);
-      g_assert (s);
-      if (text->text_input != s)
-	swfdec_text_field_movie_set_text (text, s, text->text->html);
-    } else {
-      SWFDEC_LOG ("setting variable %s to \"%s\"", text->variable,
-	  text->text_input ? text->text_input : "");
-      s = text->text_input ? swfdec_as_context_get_string (parent->context,
-	  text->text_input) : SWFDEC_AS_STR_EMPTY;
-      SWFDEC_AS_VALUE_SET_STRING (&val, s);
-      swfdec_as_context_eval_set (parent->context, parent, text->variable,
-	  &val);
-    }
+    str = swfdec_text_field_movie_get_variable_text (text);
+    swfdec_text_field_movie_set_text (text, str, text->text->html);
   }
 }
 
@@ -672,7 +633,6 @@ swfdec_text_field_movie_class_init (SwfdecTextFieldMovieClass * g_class)
   movie_class->init_movie = swfdec_text_field_movie_init_movie;
   movie_class->update_extents = swfdec_text_field_movie_update_extents;
   movie_class->render = swfdec_text_field_movie_render;
-  movie_class->iterate_start = swfdec_text_field_movie_iterate;
 }
 
 static void
@@ -760,14 +720,330 @@ swfdec_text_field_movie_set_text_format (SwfdecTextFieldMovie *text,
   swfdec_text_field_movie_format_changed (text);
 }
 
+static void
+swfdec_text_field_movie_set_variable_text (SwfdecTextFieldMovie *text,
+    const char *value)
+{
+  SwfdecAsObject *parent;
+  SwfdecAsValue val;
+
+  g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
+  g_return_if_fail (text->variable != NULL);
+
+  // FIXME: proper variable lookup
+  parent = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (text)->parent);
+
+  SWFDEC_AS_VALUE_SET_STRING (&val, value);
+  swfdec_as_object_set_variable (parent, text->variable, &val);
+}
+
+const char *
+swfdec_text_field_movie_get_variable_text (SwfdecTextFieldMovie *text)
+{
+  SwfdecAsObject *parent;
+  SwfdecAsValue val;
+
+  g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text), NULL);
+  g_return_val_if_fail (text->variable != NULL, NULL);
+
+  // FIXME: proper variable lookup
+  parent = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (text)->parent);
+
+  if (!swfdec_as_object_get_variable (parent, text->variable, &val))
+    return NULL;
+
+  return swfdec_as_value_to_string (parent->context, &val);
+}
+
+static const char *
+align_to_string (SwfdecTextAlign align)
+{
+  switch (align) {
+    case SWFDEC_TEXT_ALIGN_LEFT:
+      return "LEFT";
+    case SWFDEC_TEXT_ALIGN_RIGHT:
+      return "RIGHT";
+    case SWFDEC_TEXT_ALIGN_CENTER:
+      return "CENTER";
+    case SWFDEC_TEXT_ALIGN_JUSTIFY:
+      return "JUSTIFY";
+    default:
+      g_assert_not_reached ();
+  }
+}
+
+/*
+ * Order of tags:
+ * TEXTFORMAT / P or LI / FONT / A / B / I / U
+ *
+ * Order of attributes:
+ * TEXTFORMAT:
+ * LEFTMARGIN / RIGHTMARGIN / INDENT / LEADING / BLOCKINDENT / TABSTOPS
+ * P: ALIGN
+ * LI: none
+ * FONT: FACE / SIZE / COLOR / LETTERSPACING / KERNING
+ * A: HREF / TARGET
+ * B: none
+ * I: none
+ * U: none
+ */
+static GString *
+swfdec_text_field_movie_html_text_append_paragraph (SwfdecTextFieldMovie *text,
+    GString *string, guint start_index, guint end_index)
+{
+  SwfdecTextFormat *format, *format_prev, *format_font;
+  GSList *iter, *fonts, *iter_font;
+  guint index_, index_prev;
+  gboolean textformat, bullet, font;
+  char *escaped;
+
+  g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text), string);
+  g_return_val_if_fail (string != NULL, string);
+  g_return_val_if_fail (start_index < end_index, string);
+
+  g_return_val_if_fail (text->formats != NULL, string);
+  for (iter = text->formats; iter->next != NULL &&
+      ((SwfdecFormatIndex *)(iter->next->data))->index <= start_index;
+      iter = iter->next);
+
+  index_ = start_index;
+  format = ((SwfdecFormatIndex *)(iter->data))->format;
+
+  if (format->left_margin != 0 || format->right_margin != 0 ||
+      format->indent != 0 || format->leading != 0 ||
+      format->block_indent != 0 ||
+      swfdec_as_array_get_length (format->tab_stops) > 0)
+  {
+    string = g_string_append (string, "<TEXTFORMAT");
+    if (format->left_margin) {
+      g_string_append_printf (string, " LEFTMARGIN=\"%i\"",
+	  format->left_margin);
+    }
+    if (format->right_margin) {
+      g_string_append_printf (string, " RIGHTMARGIN=\"%i\"",
+	  format->right_margin);
+    }
+    if (format->indent)
+      g_string_append_printf (string, " INDENT=\"%i\"", format->indent);
+    if (format->leading)
+      g_string_append_printf (string, " LEADING=\"%i\"", format->leading);
+    if (format->block_indent) {
+      g_string_append_printf (string, " BLOCKINDENT=\"%i\"",
+	  format->block_indent);
+    }
+    if (swfdec_as_array_get_length (format->tab_stops) > 0) {
+      SwfdecAsValue val;
+      SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT  (format->tab_stops));
+      g_string_append_printf (string, " TABSTOPS=\"%s\"",
+	  swfdec_as_value_to_string (SWFDEC_AS_OBJECT
+	    (format->tab_stops)->context, &val));
+    }
+    string = g_string_append (string, ">");
+
+    textformat = TRUE;
+  }
+  else
+  {
+    textformat = FALSE;
+  }
+
+  if (format->bullet) {
+    string = g_string_append (string, "<LI>");
+    bullet = TRUE;
+  } else {
+    g_string_append_printf (string, "<P ALIGN=\"%s\">",
+	align_to_string (format->align));
+    bullet = FALSE;
+  }
+
+  // note we don't escape format->font, even thought it can have evil chars
+  g_string_append_printf (string, "<FONT FACE=\"%s\" SIZE=\"%i\" COLOR=\"#%06X\" LETTERSPACING=\"%i\" KERNING=\"%i\">",
+      format->font, format->size, format->color, (int)format->letter_spacing,
+      (format->kerning ? 1 : 0));
+  fonts = g_slist_prepend (NULL, format);
+
+  if (format->url != SWFDEC_AS_STR_EMPTY)
+    g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
+	format->url, format->target);
+  if (format->bold)
+    string = g_string_append (string, "<B>");
+  if (format->italic)
+    string = g_string_append (string, "<I>");
+  if (format->underline)
+    string = g_string_append (string, "<U>");
+
+  // special case: use <= instead of < to add some extra markup
+  for (iter = iter->next;
+      iter != NULL && ((SwfdecFormatIndex *)(iter->data))->index <= end_index;
+      iter = iter->next)
+  {
+    index_prev = index_;
+    format_prev = format;
+    index_ = ((SwfdecFormatIndex *)(iter->data))->index;
+    format = ((SwfdecFormatIndex *)(iter->data))->format;
+
+    escaped = swfdec_xml_escape_len (text->text_display + index_prev,
+	index_ - index_prev);
+    string = g_string_append (string, escaped);
+    g_free (escaped);
+    escaped = NULL;
+
+    // Figure out what tags need to be rewritten
+    if (format->font != format_prev->font ||
+	format->size != format_prev->size ||
+	format->color != format_prev->color ||
+	(int)format->letter_spacing != (int)format_prev->letter_spacing ||
+	format->kerning != format_prev->kerning) {
+      font = TRUE;
+    } else if (format->url == format_prev->url &&
+	format->target == format_prev->target &&
+	format->bold == format_prev->bold &&
+	format->italic == format_prev->italic &&
+	format->underline == format_prev->underline) {
+      continue;
+    }
+
+    // Close tags
+    for (iter_font = fonts; iter_font != NULL; iter_font = iter_font->next)
+    {
+      format_font = (SwfdecTextFormat *)iter_font->data;
+      if (format->font == format_font->font &&
+	format->size == format_font->size &&
+	format->color == format_font->color &&
+	(int)format->letter_spacing == (int)format_font->letter_spacing &&
+	format->kerning == format_font->kerning) {
+	break;
+      }
+    }
+    if (iter_font != NULL) {
+      while (fonts != iter_font) {
+	string = g_string_append (string, "</FONT>");
+	fonts = g_slist_remove (fonts, fonts->data);
+      }
+    }
+    if (format_prev->underline)
+      string = g_string_append (string, "</U>");
+    if (format_prev->italic)
+      string = g_string_append (string, "</I>");
+    if (format_prev->bold)
+      string = g_string_append (string, "</B>");
+    if (format_prev->url != SWFDEC_AS_STR_EMPTY)
+      string = g_string_append (string, "</A>");
+
+    // Open tags
+    format_font = (SwfdecTextFormat *)fonts->data;
+    if (font && (format->font != format_font->font ||
+	 format->size != format_font->size ||
+	 format->color != format_font->color ||
+	 (int)format->letter_spacing != (int)format_font->letter_spacing ||
+	 format->kerning != format_font->kerning))
+    {
+      fonts = g_slist_prepend (fonts, format);
+
+      string = g_string_append (string, "<FONT");
+      // note we don't escape format->font, even thought it can have evil chars
+      if (format->font != format_font->font)
+	g_string_append_printf (string, " FACE=\"%s\"", format->font);
+      if (format->size != format_font->size)
+	g_string_append_printf (string, " SIZE=\"%i\"", format->size);
+      if (format->color != format_font->color)
+	g_string_append_printf (string, " COLOR=\"#%06X\"", format->color);
+      if ((int)format->letter_spacing != (int)format_font->letter_spacing) {
+	g_string_append_printf (string, " LETTERSPACING=\"%i\"",
+	    (int)format->letter_spacing);
+      }
+      if (format->kerning != format_font->kerning) {
+	g_string_append_printf (string, " KERNING=\"%i\"",
+	    (format->kerning ? 1 : 0));
+      }
+      string = g_string_append (string, ">");
+    }
+    if (format->url != SWFDEC_AS_STR_EMPTY) {
+      g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
+	  format->url, format->target);
+    }
+    if (format->bold)
+      string = g_string_append (string, "<B>");
+    if (format->italic)
+      string = g_string_append (string, "<I>");
+    if (format->underline)
+      string = g_string_append (string, "<U>");
+  }
+
+  escaped = swfdec_xml_escape_len (text->text_display + index_,
+      end_index - index_);
+  string = g_string_append (string, escaped);
+  g_free (escaped);
+
+  if (format->underline)
+    string = g_string_append (string, "</U>");
+  if (format->italic)
+    string = g_string_append (string, "</I>");
+  if (format->bold)
+    string = g_string_append (string, "</B>");
+  if (format->url != SWFDEC_AS_STR_EMPTY)
+    string = g_string_append (string, "</A>");
+  for (iter = fonts; iter != NULL; iter = iter->next)
+    string = g_string_append (string, "</FONT>");
+  g_slist_free (fonts);
+  if (bullet) {
+    string = g_string_append (string, "</LI>");
+  } else {
+    string = g_string_append (string, "</P>");
+  }
+  if (textformat)
+    string = g_string_append (string, "</TEXTFORMAT>");
+
+  return string;
+}
+
+const char *
+swfdec_text_field_movie_get_html_text (SwfdecTextFieldMovie *text)
+{
+  const char *p, *end;
+  GString *string;
+
+  g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text),
+      SWFDEC_AS_STR_EMPTY);
+
+  if (text->text_display == NULL)
+    return SWFDEC_AS_STR_EMPTY;
+
+  if (text->text->html == FALSE)
+    return text->text_display;
+
+  string = g_string_new ("");
+
+  p = text->text_display;
+  while (*p != '\0') {
+    end = strchr (p, '\r');
+    if (end == NULL)
+      end = strchr (p, '\0');
+
+    string = swfdec_text_field_movie_html_text_append_paragraph (text, string,
+	p - text->text_display, end - text->text_display);
+
+    if (*end == '\r') {
+      p = end + 1;
+    } else {
+      p = end;
+    }
+  }
+
+  return swfdec_as_context_give_string (SWFDEC_AS_OBJECT (text)->context,
+      g_string_free (string, FALSE));
+}
+
 void
 swfdec_text_field_movie_set_text (SwfdecTextFieldMovie *text, const char *str,
     gboolean html)
 {
   SwfdecFormatIndex *block;
   GSList *iter;
+  const char *html_text, *variable_text;
 
   g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
+  g_return_if_fail (str != NULL);
 
   text->text_input = str;
 
@@ -808,5 +1084,13 @@ swfdec_text_field_movie_set_text (SwfdecTextFieldMovie *text, const char *str,
     }
   }
 
+  if (text->variable != NULL) {
+    html_text = swfdec_text_field_movie_get_html_text (text);
+    variable_text = swfdec_text_field_movie_get_variable_text (text);
+
+    if (html_text != variable_text)
+      swfdec_text_field_movie_set_variable_text (text, html_text);
+  }
+
   swfdec_text_field_movie_format_changed (text);
 }
diff --git a/libswfdec/swfdec_text_field_movie.h b/libswfdec/swfdec_text_field_movie.h
index d7bbb03..3c31c8d 100644
--- a/libswfdec/swfdec_text_field_movie.h
+++ b/libswfdec/swfdec_text_field_movie.h
@@ -88,6 +88,8 @@ void		swfdec_text_field_movie_set_text_format	(SwfdecTextFieldMovie *	text,
 							 guint			end_index);
 void		swfdec_text_field_movie_set_scroll	(SwfdecTextFieldMovie *	text,
 							 int			value);
+const char *	swfdec_text_field_movie_get_variable_text (SwfdecTextFieldMovie *	text);
+const char *	swfdec_text_field_movie_get_html_text	(SwfdecTextFieldMovie *		text);
 
 /* implemented in swfdec_text_field_movie_as.c */
 void		swfdec_text_field_movie_init_properties	(SwfdecAsContext *	cx);
diff --git a/libswfdec/swfdec_text_field_movie_as.c b/libswfdec/swfdec_text_field_movie_as.c
index f757997..f579d21 100644
--- a/libswfdec/swfdec_text_field_movie_as.c
+++ b/libswfdec/swfdec_text_field_movie_as.c
@@ -32,7 +32,6 @@
 #include "swfdec_as_internal.h"
 #include "swfdec_as_context.h"
 #include "swfdec_as_frame_internal.h"
-#include "swfdec_xml.h"
 #include "swfdec_internal.h"
 #include "swfdec_player_internal.h"
 
@@ -72,8 +71,7 @@ swfdec_text_field_movie_get_text (SwfdecAsContext *cx, SwfdecAsObject *object,
   SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
 
   SWFDEC_AS_VALUE_SET_STRING (ret, (text->text_display != NULL ?
-	swfdec_as_context_get_string (cx, text->text_display) :
-	SWFDEC_AS_STR_EMPTY));
+	text->text_display : SWFDEC_AS_STR_EMPTY));
 }
 
 static void
@@ -114,289 +112,17 @@ swfdec_text_field_movie_set_html (SwfdecAsContext *cx, SwfdecAsObject *object,
   text->text->html = value;
 }
 
-static const char *
-align_to_string (SwfdecTextAlign align)
-{
-  switch (align) {
-    case SWFDEC_TEXT_ALIGN_LEFT:
-      return "LEFT";
-    case SWFDEC_TEXT_ALIGN_RIGHT:
-      return "RIGHT";
-    case SWFDEC_TEXT_ALIGN_CENTER:
-      return "CENTER";
-    case SWFDEC_TEXT_ALIGN_JUSTIFY:
-      return "JUSTIFY";
-    default:
-      g_assert_not_reached ();
-  }
-}
-
-/*
- * Order of tags:
- * TEXTFORMAT / P or LI / FONT / A / B / I / U
- *
- * Order of attributes:
- * TEXTFORMAT:
- * LEFTMARGIN / RIGHTMARGIN / INDENT / LEADING / BLOCKINDENT / TABSTOPS
- * P: ALIGN
- * LI: none
- * FONT: FACE / SIZE / COLOR / LETTERSPACING / KERNING
- * A: HREF / TARGET
- * B: none
- * I: none
- * U: none
- */
-static GString *
-swfdec_text_field_movie_htmlText_append_paragraph (SwfdecTextFieldMovie *text,
-    GString *string, guint start_index, guint end_index)
-{
-  SwfdecTextFormat *format, *format_prev, *format_font;
-  GSList *iter, *fonts, *iter_font;
-  guint index_, index_prev;
-  gboolean textformat, bullet, font;
-  char *escaped;
-
-  g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text), string);
-  g_return_val_if_fail (string != NULL, string);
-  g_return_val_if_fail (start_index < end_index, string);
-
-  g_return_val_if_fail (text->formats != NULL, string);
-  for (iter = text->formats; iter->next != NULL &&
-      ((SwfdecFormatIndex *)(iter->next->data))->index <= start_index;
-      iter = iter->next);
-
-  index_ = start_index;
-  format = ((SwfdecFormatIndex *)(iter->data))->format;
-
-  if (format->left_margin != 0 || format->right_margin != 0 ||
-      format->indent != 0 || format->leading != 0 ||
-      format->block_indent != 0 ||
-      swfdec_as_array_get_length (format->tab_stops) > 0)
-  {
-    string = g_string_append (string, "<TEXTFORMAT");
-    if (format->left_margin) {
-      g_string_append_printf (string, " LEFTMARGIN=\"%i\"",
-	  format->left_margin);
-    }
-    if (format->right_margin) {
-      g_string_append_printf (string, " RIGHTMARGIN=\"%i\"",
-	  format->right_margin);
-    }
-    if (format->indent)
-      g_string_append_printf (string, " INDENT=\"%i\"", format->indent);
-    if (format->leading)
-      g_string_append_printf (string, " LEADING=\"%i\"", format->leading);
-    if (format->block_indent) {
-      g_string_append_printf (string, " BLOCKINDENT=\"%i\"",
-	  format->block_indent);
-    }
-    if (swfdec_as_array_get_length (format->tab_stops) > 0) {
-      SwfdecAsValue val;
-      SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT  (format->tab_stops));
-      g_string_append_printf (string, " TABSTOPS=\"%s\"",
-	  swfdec_as_value_to_string (SWFDEC_AS_OBJECT
-	    (format->tab_stops)->context, &val));
-    }
-    string = g_string_append (string, ">");
-
-    textformat = TRUE;
-  }
-  else
-  {
-    textformat = FALSE;
-  }
-
-  if (format->bullet) {
-    string = g_string_append (string, "<LI>");
-    bullet = TRUE;
-  } else {
-    g_string_append_printf (string, "<P ALIGN=\"%s\">",
-	align_to_string (format->align));
-    bullet = FALSE;
-  }
-
-  // note we don't escape format->font, even thought it can have evil chars
-  g_string_append_printf (string, "<FONT FACE=\"%s\" SIZE=\"%i\" COLOR=\"#%06X\" LETTERSPACING=\"%i\" KERNING=\"%i\">",
-      format->font, format->size, format->color, (int)format->letter_spacing,
-      (format->kerning ? 1 : 0));
-  fonts = g_slist_prepend (NULL, format);
-
-  if (format->url != SWFDEC_AS_STR_EMPTY)
-    g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
-	format->url, format->target);
-  if (format->bold)
-    string = g_string_append (string, "<B>");
-  if (format->italic)
-    string = g_string_append (string, "<I>");
-  if (format->underline)
-    string = g_string_append (string, "<U>");
-
-  // special case: use <= instead of < to add some extra markup
-  for (iter = iter->next;
-      iter != NULL && ((SwfdecFormatIndex *)(iter->data))->index <= end_index;
-      iter = iter->next)
-  {
-    index_prev = index_;
-    format_prev = format;
-    index_ = ((SwfdecFormatIndex *)(iter->data))->index;
-    format = ((SwfdecFormatIndex *)(iter->data))->format;
-
-    escaped = swfdec_xml_escape_len (text->text_display + index_prev,
-	index_ - index_prev);
-    string = g_string_append (string, escaped);
-    g_free (escaped);
-    escaped = NULL;
-
-    // Figure out what tags need to be rewritten
-    if (format->font != format_prev->font ||
-	format->size != format_prev->size ||
-	format->color != format_prev->color ||
-	(int)format->letter_spacing != (int)format_prev->letter_spacing ||
-	format->kerning != format_prev->kerning) {
-      font = TRUE;
-    } else if (format->url == format_prev->url &&
-	format->target == format_prev->target &&
-	format->bold == format_prev->bold &&
-	format->italic == format_prev->italic &&
-	format->underline == format_prev->underline) {
-      continue;
-    }
-
-    // Close tags
-    for (iter_font = fonts; iter_font != NULL; iter_font = iter_font->next)
-    {
-      format_font = (SwfdecTextFormat *)iter_font->data;
-      if (format->font == format_font->font &&
-	format->size == format_font->size &&
-	format->color == format_font->color &&
-	(int)format->letter_spacing == (int)format_font->letter_spacing &&
-	format->kerning == format_font->kerning) {
-	break;
-      }
-    }
-    if (iter_font != NULL) {
-      while (fonts != iter_font) {
-	string = g_string_append (string, "</FONT>");
-	fonts = g_slist_remove (fonts, fonts->data);
-      }
-    }
-    if (format_prev->underline)
-      string = g_string_append (string, "</U>");
-    if (format_prev->italic)
-      string = g_string_append (string, "</I>");
-    if (format_prev->bold)
-      string = g_string_append (string, "</B>");
-    if (format_prev->url != SWFDEC_AS_STR_EMPTY)
-      string = g_string_append (string, "</A>");
-
-    // Open tags
-    format_font = (SwfdecTextFormat *)fonts->data;
-    if (font && (format->font != format_font->font ||
-	 format->size != format_font->size ||
-	 format->color != format_font->color ||
-	 (int)format->letter_spacing != (int)format_font->letter_spacing ||
-	 format->kerning != format_font->kerning))
-    {
-      fonts = g_slist_prepend (fonts, format);
-
-      string = g_string_append (string, "<FONT");
-      // note we don't escape format->font, even thought it can have evil chars
-      if (format->font != format_font->font)
-	g_string_append_printf (string, " FACE=\"%s\"", format->font);
-      if (format->size != format_font->size)
-	g_string_append_printf (string, " SIZE=\"%i\"", format->size);
-      if (format->color != format_font->color)
-	g_string_append_printf (string, " COLOR=\"#%06X\"", format->color);
-      if ((int)format->letter_spacing != (int)format_font->letter_spacing) {
-	g_string_append_printf (string, " LETTERSPACING=\"%i\"",
-	    (int)format->letter_spacing);
-      }
-      if (format->kerning != format_font->kerning) {
-	g_string_append_printf (string, " KERNING=\"%i\"",
-	    (format->kerning ? 1 : 0));
-      }
-      string = g_string_append (string, ">");
-    }
-    if (format->url != SWFDEC_AS_STR_EMPTY) {
-      g_string_append_printf (string, "<A HREF=\"%s\" TARGET=\"%s\">",
-	  format->url, format->target);
-    }
-    if (format->bold)
-      string = g_string_append (string, "<B>");
-    if (format->italic)
-      string = g_string_append (string, "<I>");
-    if (format->underline)
-      string = g_string_append (string, "<U>");
-  }
-
-  escaped = swfdec_xml_escape_len (text->text_display + index_,
-      end_index - index_);
-  string = g_string_append (string, escaped);
-  g_free (escaped);
-
-  if (format->underline)
-    string = g_string_append (string, "</U>");
-  if (format->italic)
-    string = g_string_append (string, "</I>");
-  if (format->bold)
-    string = g_string_append (string, "</B>");
-  if (format->url != SWFDEC_AS_STR_EMPTY)
-    string = g_string_append (string, "</A>");
-  for (iter = fonts; iter != NULL; iter = iter->next)
-    string = g_string_append (string, "</FONT>");
-  g_slist_free (fonts);
-  if (bullet) {
-    string = g_string_append (string, "</LI>");
-  } else {
-    string = g_string_append (string, "</P>");
-  }
-  if (textformat)
-    string = g_string_append (string, "</TEXTFORMAT>");
-
-  return string;
-}
-
 static void
 swfdec_text_field_movie_get_htmlText (SwfdecAsContext *cx,
     SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
     SwfdecAsValue *ret)
 {
   SwfdecTextFieldMovie *text;
-  const char *p, *end;
-  GString *string;
 
   SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
 
-  if (text->text->html == FALSE) {
-    swfdec_text_field_movie_get_text (cx, object, argc, argv, ret);
-    return;
-  }
-
-  if (text->text_display == NULL) {
-    SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
-    return;
-  }
-
-  string = g_string_new ("");
-
-  p = text->text_display;
-  while (*p != '\0') {
-    end = strchr (p, '\r');
-    if (end == NULL)
-      end = strchr (p, '\0');
-
-    string = swfdec_text_field_movie_htmlText_append_paragraph (text, string,
-	p - text->text_display, end - text->text_display);
-
-    if (*end == '\r') {
-      p = end + 1;
-    } else {
-      p = end;
-    }
-  }
-
   SWFDEC_AS_VALUE_SET_STRING (ret,
-      swfdec_as_context_give_string (cx, g_string_free (string, FALSE)));
+      swfdec_text_field_movie_get_html_text (text));
 }
 
 static void
@@ -577,6 +303,45 @@ swfdec_text_field_movie_do_set_type (SwfdecAsContext *cx,
   }
 }
 
+static void
+swfdec_text_field_movie_do_get_variable (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
+
+  if (text->variable) {
+    SWFDEC_AS_VALUE_SET_STRING (ret, text->variable);
+  } else {
+    SWFDEC_AS_VALUE_SET_NULL (ret);
+  }
+}
+
+static void
+swfdec_text_field_movie_do_set_variable (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+  const char *value, *str;
+
+  if (argc > 0)
+    swfdec_as_value_to_number (cx, &argv[0]);
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "s", &value);
+
+  if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
+      SWFDEC_AS_VALUE_IS_NULL (&argv[0]) || value == SWFDEC_AS_STR_EMPTY) {
+    text->variable = NULL;
+  } else if (value != text->variable) {
+    text->variable = value;
+    str = swfdec_text_field_movie_get_variable_text (text);
+    swfdec_text_field_movie_set_text (text, str, text->text->html);
+  }
+}
+
 /*
  * Native properties: Background & border
  */
@@ -1150,9 +915,9 @@ swfdec_text_field_movie_init_properties (SwfdecAsContext *cx)
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_type,
       swfdec_text_field_movie_do_get_type,
       swfdec_text_field_movie_do_set_type);
-  /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_variable,
-      swfdec_text_field_movie_get_variable,
-      swfdec_text_field_movie_set_variable);*/
+  swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_variable,
+      swfdec_text_field_movie_do_get_variable,
+      swfdec_text_field_movie_do_set_variable);
 
   // info
   /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_textHeight,
commit f0537ab6f2eaf2c8c2d2c22baa0e9ce6cc6f7a76
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon Oct 15 14:13:42 2007 +0300

    Add selectable and password properties to TextField
    
    Both set the internal state of the object, but using it is not yet implemented

diff --git a/libswfdec/swfdec_as_strings.c b/libswfdec/swfdec_as_strings.c
index 8a5ad49..a47dee8 100644
--- a/libswfdec/swfdec_as_strings.c
+++ b/libswfdec/swfdec_as_strings.c
@@ -406,5 +406,7 @@ const char swfdec_as_strings[] =
   SWFDEC_AS_CONSTANT_STRING ("dynamic")
   SWFDEC_AS_CONSTANT_STRING ("scroll")
   SWFDEC_AS_CONSTANT_STRING ("maxChars")
+  SWFDEC_AS_CONSTANT_STRING ("selectable")
+  SWFDEC_AS_CONSTANT_STRING ("password")
   /* add more here */
 ;
diff --git a/libswfdec/swfdec_text_field_movie_as.c b/libswfdec/swfdec_text_field_movie_as.c
index d480525..f757997 100644
--- a/libswfdec/swfdec_text_field_movie_as.c
+++ b/libswfdec/swfdec_text_field_movie_as.c
@@ -513,6 +513,35 @@ swfdec_text_field_movie_set_multiline (SwfdecAsContext *cx,
 }
 
 static void
+swfdec_text_field_movie_get_selectable (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
+
+  SWFDEC_AS_VALUE_SET_BOOLEAN (ret, text->text->selectable);
+}
+
+static void
+swfdec_text_field_movie_set_selectable (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+  gboolean value;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "b", &value);
+
+  swfdec_as_value_to_number (cx, &argv[0]);
+
+  text->text->selectable = value;
+
+  // FIXME: If selection made and removing selectable force redraw?
+}
+
+static void
 swfdec_text_field_movie_do_get_type (SwfdecAsContext *cx,
     SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
     SwfdecAsValue *ret)
@@ -771,6 +800,36 @@ swfdec_text_field_movie_set_autoSize (SwfdecAsContext *cx,
 }
 
 static void
+swfdec_text_field_movie_get_password (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
+
+  SWFDEC_AS_VALUE_SET_BOOLEAN (ret, text->text->password);
+}
+
+static void
+swfdec_text_field_movie_set_password (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+  gboolean value;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "b", &value);
+
+  swfdec_as_value_to_number (cx, &argv[0]);
+
+  if (text->text->password != value) {
+    text->text->password = value;
+    swfdec_movie_invalidate (SWFDEC_MOVIE (text));
+  }
+}
+
+static void
 swfdec_text_field_movie_get_wordWrap (SwfdecAsContext *cx,
     SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
     SwfdecAsValue *ret)
@@ -1085,9 +1144,9 @@ swfdec_text_field_movie_init_properties (SwfdecAsContext *cx)
   /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_restrict,
       swfdec_text_field_movie_get_restrict,
       swfdec_text_field_movie_set_restrict);*/
-  /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_selectable,
+  swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_selectable,
       swfdec_text_field_movie_get_selectable,
-      swfdec_text_field_movie_set_selectable);*/
+      swfdec_text_field_movie_set_selectable);
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_type,
       swfdec_text_field_movie_do_get_type,
       swfdec_text_field_movie_do_set_type);
@@ -1140,9 +1199,9 @@ swfdec_text_field_movie_init_properties (SwfdecAsContext *cx)
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_autoSize,
       swfdec_text_field_movie_get_autoSize,
       swfdec_text_field_movie_set_autoSize);
-  /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_password,
+  swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_password,
       swfdec_text_field_movie_get_password,
-      swfdec_text_field_movie_set_password);*/
+      swfdec_text_field_movie_set_password);
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_wordWrap,
       swfdec_text_field_movie_get_wordWrap,
       swfdec_text_field_movie_set_wordWrap);
commit 55255cf00370ca06b978b1669f5c26395ab3cdb8
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon Oct 15 14:03:08 2007 +0300

    Add maxChars property to TextField
    
    Only sets the internal state now, doesn't actually get used since input is not
    implemented yet

diff --git a/libswfdec/swfdec_as_strings.c b/libswfdec/swfdec_as_strings.c
index 957f484..8a5ad49 100644
--- a/libswfdec/swfdec_as_strings.c
+++ b/libswfdec/swfdec_as_strings.c
@@ -405,5 +405,6 @@ const char swfdec_as_strings[] =
   SWFDEC_AS_CONSTANT_STRING ("input")
   SWFDEC_AS_CONSTANT_STRING ("dynamic")
   SWFDEC_AS_CONSTANT_STRING ("scroll")
+  SWFDEC_AS_CONSTANT_STRING ("maxChars")
   /* add more here */
 ;
diff --git a/libswfdec/swfdec_text_field.c b/libswfdec/swfdec_text_field.c
index a594bbd..064dcd0 100644
--- a/libswfdec/swfdec_text_field.c
+++ b/libswfdec/swfdec_text_field.c
@@ -83,7 +83,6 @@ static void
 swfdec_text_field_init (SwfdecTextField * text)
 {
   text->scroll = 1;
-  text->max_length = G_MAXUINT;
 }
 
 SwfdecLayout *
@@ -434,7 +433,9 @@ tag_func_define_edit_text (SwfdecSwfDecoder * s, guint tag)
     text->color = SWFDEC_COLOR_COMBINE (255, 255, 255, 255);
   }
   if (has_max_length) {
-    text->max_length = swfdec_bits_get_u16 (b);
+    text->max_chars = swfdec_bits_get_u16 (b);
+  } else {
+    text->max_chars = 0;
   }
   if (has_layout) {
     guint align = swfdec_bits_get_u8 (b);
diff --git a/libswfdec/swfdec_text_field.h b/libswfdec/swfdec_text_field.h
index 1609a52..f3cd10d 100644
--- a/libswfdec/swfdec_text_field.h
+++ b/libswfdec/swfdec_text_field.h
@@ -86,7 +86,7 @@ struct _SwfdecTextField
 
   gboolean		input;
   gboolean		password;
-  guint			max_length;
+  int			max_chars;
   gboolean		selectable;
 
   gboolean		embed_fonts;
diff --git a/libswfdec/swfdec_text_field_movie_as.c b/libswfdec/swfdec_text_field_movie_as.c
index 7e8e20e..d480525 100644
--- a/libswfdec/swfdec_text_field_movie_as.c
+++ b/libswfdec/swfdec_text_field_movie_as.c
@@ -454,6 +454,38 @@ swfdec_text_field_movie_set_condenseWhite (SwfdecAsContext *cx,
 }
 
 static void
+swfdec_text_field_movie_get_maxChars (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
+
+  if (text->text->max_chars != 0) {
+    SWFDEC_AS_VALUE_SET_INT (ret, text->text->max_chars);
+  } else {
+    SWFDEC_AS_VALUE_SET_NULL (ret);
+  }
+}
+
+static void
+swfdec_text_field_movie_set_maxChars (SwfdecAsContext *cx,
+    SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
+    SwfdecAsValue *ret)
+{
+  SwfdecTextFieldMovie *text;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FIELD_MOVIE, &text, "");
+
+  if (argc < 1)
+    return;
+
+  swfdec_as_value_to_number (cx, &argv[0]);
+  text->text->max_chars = swfdec_as_value_to_integer (cx, &argv[0]);
+}
+
+static void
 swfdec_text_field_movie_get_multiline (SwfdecAsContext *cx,
     SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
     SwfdecAsValue *ret)
@@ -1044,9 +1076,9 @@ swfdec_text_field_movie_init_properties (SwfdecAsContext *cx)
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_condenseWhite,
       swfdec_text_field_movie_get_condenseWhite,
       swfdec_text_field_movie_set_condenseWhite);
-  /*swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_maxChars,
+  swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_maxChars,
       swfdec_text_field_movie_get_maxChars,
-      swfdec_text_field_movie_set_maxChars);*/
+      swfdec_text_field_movie_set_maxChars);
   swfdec_text_field_movie_add_variable (proto, SWFDEC_AS_STR_multiline,
       swfdec_text_field_movie_get_multiline,
       swfdec_text_field_movie_set_multiline);


More information about the Swfdec mailing list