gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r11949: Split the gigantic TextField


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11949: Split the gigantic TextField file into separate DisplayObject and ActionScript
Date: Mon, 15 Feb 2010 16:08:21 +0100
User-agent: Bazaar (2.0.3)

------------------------------------------------------------
revno: 11949 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Mon 2010-02-15 16:08:21 +0100
message:
  Split the gigantic TextField file into separate DisplayObject and ActionScript
  implementations. TextField.cpp is stil gigantic.
modified:
  libcore/TextField.cpp
  libcore/TextField.h
  libcore/asobj/Globals.cpp
  libcore/asobj/flash/text/TextField_as.cpp
  libcore/asobj/flash/text/TextField_as.h
  libcore/asobj/flash/text/text.am
  libcore/swf/DefineEditTextTag.cpp
=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp     2010-01-28 09:25:45 +0000
+++ b/libcore/TextField.cpp     2010-02-15 14:55:30 +0000
@@ -31,37 +31,30 @@
 #include "utf8.h"
 #include "log.h"
 #include "swf/DefineEditTextTag.h"
-#include "movie_definition.h" // to extract version info
 #include "MovieClip.h"
 #include "TextField.h"
 #include "flash/ui/Keyboard_as.h" // for keyboard events
 #include "movie_root.h"     // for killing focus
 #include "as_environment.h" // for parse_path
-#include "VM.h"
-#include "builtin_function.h" 
-#include "NativeFunction.h"
 #include "Font.h" 
 #include "fontlib.h" 
 #include "namedStrings.h"
-#include "AsBroadcaster.h" // for initializing self as a broadcaster
 #include "StringPredicates.h"
-#include "flash/text/TextFormat_as.h"
-#include "GnashKey.h" // key::code
+#include "text/TextFormat_as.h"
+#include "GnashKey.h"
 #include "TextRecord.h"
-#include "Global_as.h"
 #include "Point2d.h"
 #include "GnashNumeric.h"
 #include "MouseButtonState.h"
+#include "Global_as.h"
 
-#include <algorithm> // std::min
+#include <algorithm> 
 #include <string>
-#include <boost/algorithm/string/case_conv.hpp>
 #include <boost/assign/list_of.hpp>
 #include <boost/bind.hpp>
 #include <cstdlib>
 #include <cctype>
 #include <utility>
-#include <typeinfo>
 #include <map>
 
 // Text fields have a fixed 2 pixel padding for each side (regardless of 
border)
@@ -76,68 +69,6 @@
 
 namespace gnash {
 
-// Forward declarations
-namespace {
-    const char* autoSizeValueName(TextField::AutoSize val);
-    TextField::AutoSize parseAutoSize(const std::string& val);
-
-    void attachPrototypeProperties(as_object& proto);
-    void attachTextFieldStaticMembers(as_object& o);
-    void attachTextFieldInterface(as_object& o);
-
-    as_value textfield_createTextField(const fn_call& fn);
-
-    as_value textfield_variable(const fn_call& fn);
-    as_value textfield_setTextFormat(const fn_call& fn);
-    as_value textfield_getTextFormat(const fn_call& fn);
-    as_value textfield_setNewTextFormat(const fn_call& fn);
-    as_value textfield_getNewTextFormat(const fn_call& fn);
-    as_value textfield_getDepth(const fn_call& fn);
-    as_value textfield_getFontList(const fn_call& fn);
-    as_value textfield_removeTextField(const fn_call& fn);
-    as_value textfield_replaceSel(const fn_call& fn);
-    as_value textfield_replaceText(const fn_call& fn);
-
-    as_value textfield_password(const fn_call& fn);
-    as_value textfield_ctor(const fn_call& fn);
-    as_value textfield_multiline(const fn_call& fn);
-    as_value textfield_scroll(const fn_call& fn);
-    as_value textfield_maxscroll(const fn_call& fn);
-    as_value textfield_maxhscroll(const fn_call& fn);
-    as_value textfield_maxChars(const fn_call& fn);
-    as_value textfield_bottomScroll(const fn_call& fn);
-    as_value textfield_hscroll(const fn_call& fn);
-    as_value textfield_htmlText(const fn_call& fn);
-    as_value textfield_restrict(const fn_call& fn);
-    as_value textfield_background(const fn_call& fn);
-    as_value textfield_border(const fn_call& fn);
-    as_value textfield_backgroundColor(const fn_call& fn);
-    as_value textfield_borderColor(const fn_call& fn);
-    as_value textfield_text(const fn_call& fn);
-    as_value textfield_textColor(const fn_call& fn);
-    as_value textfield_embedFonts(const fn_call& fn);
-    as_value textfield_autoSize(const fn_call& fn);
-    as_value textfield_type(const fn_call& fn);
-    as_value textfield_wordWrap(const fn_call& fn);
-    as_value textfield_html(const fn_call& fn);
-    as_value textfield_selectable(const fn_call& fn);
-    as_value textfield_length(const fn_call& fn);
-    as_value textfield_textWidth(const fn_call& fn);
-    as_value textfield_textHeight(const fn_call& fn);
-}
-
-as_object*
-createTextFieldObject(Global_as& gl)
-{
-    as_value tf(gl.getMember(NSV::CLASS_TEXT_FIELD));
-    as_function* ctor = tf.to_function();
-    if (!ctor) return 0;
-    fn_call::Args args;
-    as_environment env(getVM(gl));
-    return constructInstance(*ctor, env, args);
-}
-
-
 TextField::TextField(as_object* object, DisplayObject* parent,
         const SWF::DefineEditTextTag& def)
     :
@@ -2341,46 +2272,6 @@
     }
 }
 
-/// This provides the prototype and static methods for TextField.
-//
-/// For SWF5 there is initially no prototype, for SWF6+ there is a 
-/// limited prototype. This is changed later on instantiation of a
-/// TextField.
-void
-textfield_class_init(as_object& where, const ObjectURI& uri)
-{
-
-    Global_as& gl = getGlobal(where);
-    as_object* proto = gl.createObject();
-    as_object* cl = gl.createClass(&textfield_ctor, proto);
-
-    attachTextFieldInterface(*proto);
-    attachTextFieldStaticMembers(*cl);
-             
-    where.init_member(uri, cl, as_object::DefaultFlags);
-
-    // ASSetPropFlags is called on the TextField class.
-    as_object* null = 0;
-    callMethod(&gl, NSV::PROP_AS_SET_PROP_FLAGS, cl, null, 131);
-}
-
-void
-registerTextFieldNative(as_object& global)
-{
-    VM& vm = getVM(global);
-    vm.registerNative(textfield_replaceSel, 104, 100);
-    vm.registerNative(textfield_getTextFormat, 104, 101);
-    vm.registerNative(textfield_setTextFormat, 104, 102);
-    vm.registerNative(textfield_removeTextField, 104, 103);
-    vm.registerNative(textfield_getNewTextFormat, 104, 104);
-    vm.registerNative(textfield_setNewTextFormat, 104, 105);
-    vm.registerNative(textfield_getDepth, 104, 106);
-    vm.registerNative(textfield_replaceText, 104, 107);
-
-    vm.registerNative(textfield_createTextField, 104, 200);
-    vm.registerNative(textfield_getFontList, 104, 201);
-}
-
 bool
 TextField::pointInShape(boost::int32_t x, boost::int32_t y) const
 {
@@ -2773,1061 +2664,6 @@
 
 /// TextField interface functions
 
-namespace {
-
-void
-attachPrototypeProperties(as_object& o)
-{
-    // SWF6 or higher
-    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
-
-    boost::intrusive_ptr<builtin_function> getset;
-
-    // The following properties should only be attached to the prototype
-    // on first textfield creation.
-    o.init_property(NSV::PROP_TEXT_WIDTH,
-            textfield_textWidth, textfield_textWidth);
-    o.init_property(NSV::PROP_TEXT_HEIGHT,
-            textfield_textHeight, textfield_textHeight);
-
-    Global_as& gl = getGlobal(o);
-
-    getset = gl.createFunction(textfield_variable);
-    o.init_property("variable", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_background);
-    o.init_property("background", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_text);
-    o.init_property("text", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_backgroundColor);
-    o.init_property("backgroundColor", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_border);
-    o.init_property("border", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_borderColor);
-    o.init_property("borderColor", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_textColor);
-    o.init_property("textColor", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_embedFonts);
-    o.init_property("embedFonts", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_autoSize);
-    o.init_property("autoSize", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_type);
-    o.init_property("type", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_wordWrap);
-    o.init_property("wordWrap", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_html);
-    o.init_property("html", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_selectable);
-    o.init_property("selectable", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_length);
-    o.init_property("length", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_maxscroll);
-    o.init_property("maxscroll", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_maxhscroll);
-    o.init_property("maxhscroll", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_maxChars);
-    o.init_property("maxChars", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_bottomScroll);
-    o.init_property("bottomScroll", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_scroll);
-    o.init_property("scroll", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_hscroll);
-    o.init_property("hscroll", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_restrict);
-    o.init_property("restrict", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_multiline);
-    o.init_property("multiline", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_password);
-    o.init_property("password", *getset, *getset, swf6Flags);
-    getset = gl.createFunction(textfield_htmlText);
-    o.init_property("htmlText", *getset, *getset, swf6Flags);
-}
-
-
-/// This is in fact a property of MovieClip, but it is more a TextField
-/// function, as its major number (104) in the native table shows.
-as_value
-textfield_createTextField(const fn_call& fn)
-{
-    MovieClip* ptr = ensure<IsDisplayObject<MovieClip> >(fn);
-    
-    // name, depth, x, y, width, height
-    if (fn.nargs < 6) {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField called with %d args, "
-            "expected 6 - returning undefined"), fn.nargs);
-        );
-        return as_value();
-    }
-
-    const std::string& name = fn.arg(0).to_string();
-    const int depth = toInt(fn.arg(1));
-    const int x = toInt(fn.arg(2));
-    const int y = toInt(fn.arg(3));
-    
-    int width = toInt(fn.arg(4));
-    if (width < 0) {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField: negative width (%d)"
-            " - reverting sign"), width);
-        );
-        width = -width;
-    }
-
-    int height = toInt(fn.arg(5));
-    if ( height < 0 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField: negative height (%d)"
-            " - reverting sign"), height);
-        );
-        height = -height;
-    }
-    // Set textfield bounds
-    SWFRect bounds(0, 0, pixelsToTwips(width), pixelsToTwips(height));
-
-    // Tests in actionscript.all/TextField.as show that this function must:
-    //  1. Call "new _global.TextField()" (which takes care of
-    //     assigning properties to the prototype).
-    //  2. Make that object into a TextField and put it on the display list.
-    as_object* obj = createTextFieldObject(getGlobal(fn));
-
-    DisplayObject* tf = new TextField(obj, ptr, bounds);
-
-    // Give name and mark as dynamic
-    tf->set_name(name);
-    tf->setDynamic();
-
-    // Set _x and _y
-    SWFMatrix matrix;
-    matrix.set_translation(pixelsToTwips(x), pixelsToTwips(y));
-    // update caches (although shouldn't be needed as we only set translation)
-    tf->setMatrix(matrix, true); 
-
-    ptr->addDisplayListObject(tf, depth);
-
-    if (getSWFVersion(fn) > 7) return as_value(obj);
-    return as_value(); 
-}
-
-as_value
-textfield_background(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->getDrawBackground());
-    }
-    else {
-        ptr->setDrawBackground(fn.arg(0).to_bool());
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_border(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->getDrawBorder());
-    }
-    else {
-        ptr->setDrawBorder(fn.arg(0).to_bool());
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_backgroundColor(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->getBackgroundColor().toRGB());
-    }
-    else {
-        rgba newColor;
-        newColor.parseRGB(static_cast<boost::uint32_t>(toInt(fn.arg(0))));
-        ptr->setBackgroundColor(newColor);
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_borderColor(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->getBorderColor().toRGB());
-    }
-    else {
-        rgba newColor;
-        newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_number()));
-        ptr->setBorderColor(newColor);
-    }
-
-    return as_value();
-}
-
-    
-as_value
-textfield_textColor(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        // Getter
-        return as_value(ptr->getTextColor().toRGB());
-    }
-
-    // Setter
-    rgba newColor;
-    newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_number()));
-    ptr->setTextColor(newColor);
-
-    return as_value();
-}
-
-as_value
-textfield_embedFonts(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        // Getter
-        return as_value(ptr->getEmbedFonts());
-    }
-
-    // Setter
-    ptr->setEmbedFonts(fn.arg(0).to_bool());
-    return as_value();
-}
-
-as_value
-textfield_wordWrap(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->doWordWrap());
-    }
-    else {
-        ptr->setWordWrap(fn.arg(0).to_bool());
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_html(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (fn.nargs == 0) {
-        return as_value(ptr->doHtml());
-    }
-    else {
-        ptr->setHtml( fn.arg(0).to_bool() );
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_selectable(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        return as_value(ptr->isSelectable());
-    }
-    else // setter
-    {
-        ptr->setSelectable( fn.arg(0).to_bool() );
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_length(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        const std::string& s = ptr->get_text_value();
-        return as_value(s.length()); // TOCHECK: utf-8 ?
-    }
-    else // setter
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("Attempt to set length property of TextField %s"),
-            ptr->getTarget());
-        );
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_textHeight(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        // Return the height, in pixels, of the text as laid out.
-        // (I.e. the actual text content, not our defined
-        // bounding box.)
-        //
-        // In local coords.  Verified against Macromedia Flash.
-        return as_value(twipsToPixels(ptr->getTextBoundingBox().height()));
-
-    }
-    else // setter
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("Attempt to set read-only %s property of TextField "
-                "%s"), "textHeight", ptr->getTarget());
-        );
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_textWidth(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        // Return the width, in pixels, of the text as laid out.
-        // (I.e. the actual text content, not our defined
-        // bounding box.)
-        //
-        // In local coords.  Verified against Macromedia Flash.
-        return as_value(twipsToPixels(ptr->getTextBoundingBox().width()));
-
-    }
-    else // setter
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("Attempt to set read-only %s property of TextField %s"),
-            "textWidth", ptr->getTarget());
-        );
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_autoSize(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        return autoSizeValueName(ptr->getAutoSize());
-    }
-    else // setter
-    {
-        const as_value& arg = fn.arg(0);
-        if (arg.is_bool()) {
-            if (arg.to_bool()) {
-                // True equates to left, every other bool to none.
-                ptr->setAutoSize(TextField::AUTOSIZE_LEFT);
-            }
-            else {
-                ptr->setAutoSize(TextField::AUTOSIZE_NONE);
-            }
-        }
-        else {
-            std::string strval = arg.to_string();
-            TextField::AutoSize val = parseAutoSize(strval);
-            ptr->setAutoSize(val);
-        }
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_type(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        // getter
-        return ptr->typeValueName(ptr->getType());
-    }
-
-    // setter
-    const as_value& arg = fn.arg(0);
-    std::string strval = arg.to_string();
-    TextField::TypeValue val = ptr->parseTypeValue(strval);
-
-    IF_VERBOSE_ASCODING_ERRORS(
-        if (val == TextField::typeInvalid) {
-            log_aserror(_("Invalid value given to TextField.type: %s"), 
strval);
-        }
-    );
-    ptr->setType(val);
-    return as_value();
-}
-
-
-as_value
-textfield_variable(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs)
-    {
-        // Getter
-        const std::string& varName = text->getVariableName();
-        // An empty variable name returns null.
-        if (varName.empty()) {
-            as_value null;
-            null.set_null();
-            return null;
-        }
-        return as_value(varName);
-    }
-
-    // Setter
-    const as_value& varName = fn.arg(0);
-    if (varName.is_undefined() || varName.is_null()) {
-        text->set_variable_name("");
-    }
-    else text->set_variable_name(varName.to_string());
-
-    return as_value();
-
-}
-
-
-as_value
-textfield_getDepth(const fn_call& fn)
-{
-    // Unlike MovieClip.getDepth this works only for TextFields.
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    const int n = text->get_depth();
-    return as_value(n);
-}
-
-as_value
-textfield_getFontList(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-    LOG_ONCE(log_unimpl("TextField.getFontList()"));
-
-    return as_value();
-}
-
-as_value
-textfield_getNewTextFormat(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-    LOG_ONCE(log_unimpl("TextField.getNewTextFormat()"));
-
-    return as_value();
-}
-
-
-// This is a bit of a messy compromise. We call the TextFormat ctor (this
-// is necessary because prototype properties are not attached until that is
-// done). Then we access the relay object directly. This is because there
-// aren't enough known parameters to the TextFormat constructor to handle
-// all the values, and it isn't tested properly.
-as_value
-textfield_getTextFormat(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    Global_as& gl = getGlobal(fn);
-    as_function* ctor = gl.getMember(NSV::CLASS_TEXT_FORMAT).to_function();
-
-    if (!ctor) return as_value();
-
-    fn_call::Args args;
-    as_object* textformat = constructInstance(*ctor, fn.env(), args);
-    TextFormat_as* tf;
-
-    if (!isNativeType(textformat, tf)) {
-        return as_value();
-    }
-
-    tf->alignSet(text->getTextAlignment());
-    tf->sizeSet(text->getFontHeight());
-    tf->indentSet(text->getIndent());
-    tf->blockIndentSet(text->getBlockIndent());
-    tf->leadingSet(text->getLeading());
-    tf->leftMarginSet(text->getLeftMargin());
-    tf->rightMarginSet(text->getRightMargin());
-    tf->colorSet(text->getTextColor());
-    tf->underlinedSet(text->getUnderlined());
-
-    const Font* font = text->getFont();
-    if (font)
-    {
-        tf->fontSet(font->name());
-        tf->italicSet(font->isItalic());
-        tf->boldSet(font->isBold());
-    }
-
-    // TODO: add font color and some more
-
-    LOG_ONCE(
-        log_unimpl("TextField.getTextFormat() discards url, target, "
-            "tabStops, bullet and display")
-    );
-
-    return as_value(textformat);
-}
-
-as_value
-textfield_setTextFormat(const fn_call& fn)
-{
-
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( ! fn.nargs )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("TextField.setTextFormat(%s) : %s", ss.str(),
-            _("missing arg"))
-        );
-        return as_value();
-    }
-    else if ( fn.nargs > 2 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_debug("TextField.setTextFormat(%s) : args past the first are "
-                "unhandled by Gnash", ss.str());
-    }
-
-    TextFormat_as* tf;
-    if (!isNativeType(fn.arg(0).to_object(getGlobal(fn)), tf)) {
-
-        IF_VERBOSE_ASCODING_ERRORS(
-            std::stringstream ss; fn.dump_args(ss);
-            log_aserror("TextField.setTextFormat(%s) : %s", ss.str(), 
-                _("first argument is not a TextFormat"))
-            );
-        return as_value();
-    }
-
-    if (isAS3(fn)) {
-        // TODO: current font finding assumes we have a parent, which isn't
-        // necessarily the case in AS3. It seems the AS2 implementation is
-        // wrong anyway.
-        log_unimpl("fonts in AS3 TextField.setTextFormat");
-        return as_value();
-    }
-
-    if (tf->font())
-    {
-        const std::string& fontName = *tf->font();
-        if ( ! fontName.empty() )
-        {
-            bool bold = tf->bold() ? *tf->bold() : false;
-            bool italic = tf->italic() ? *tf->italic() : false;
-
-            // NOTE: should query movie-private font lib, not global-shared one
-            Movie* mi = text->get_root();
-            assert(mi);
-            const movie_definition* md = mi->definition();
-            assert(md);
-            Font* f = md->get_font(fontName, bold, italic);
-            if ( ! f ) f = fontlib::get_font(fontName, bold, italic);
-            text->setFont( f );
-        }
-    }
-
-    // TODO: add font color and some more
-    text->setTextFormat(*tf);
-    return as_value();
-
-}
-
-as_value
-textfield_setNewTextFormat(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-    LOG_ONCE( log_unimpl("TextField.setNewTextFormat(), we'll delegate "
-                "to setTextFormat") );
-    return textfield_setTextFormat(fn);
-}
-
-as_value
-textfield_password(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(text->password());
-    }
-    // Setter
-    text->password(fn.arg(0).to_bool());
-    return as_value();
-}
-
-as_value
-textfield_multiline(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        // Getter
-        return as_value(text->multiline());
-    }
-    // Setter
-    text->multiline(fn.arg(0).to_bool());
-    return as_value();
-}
-
-as_value
-textfield_restrict(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        // Getter
-        if (text->isRestrict()) {
-            return as_value(text->getRestrict());
-        } else {
-            as_value null;
-            null.set_null();
-            return null;
-        }
-    }
-    // Setter
-    text->setRestrict(fn.arg(0).to_string());
-    return as_value();
-}
-
-as_value
-textfield_bottomScroll(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-    LOG_ONCE(log_unimpl("TextField.bottomScroll is not complete"));
-
-
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(1 + text->getBottomScroll());
-    }
-    // Setter
-    //text->setBottomScroll(int(fn.arg(0).to_number())); READ-ONLY
-
-    return as_value();
-}
-
-as_value
-textfield_maxhscroll(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-        LOG_ONCE(log_unimpl("TextField.maxhscroll is not complete"));
-
-
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(text->getMaxHScroll());
-    }
-    // Setter
-    //text->setMaxHScroll(int(fn.arg(0).to_number())); READ-ONLY
-
-    return as_value();
-}
-
-/// TextField.maxChars().
-//
-/// This does not limit the length of the text, but rather the
-/// number of DisplayObjects that can be entered in the TextField.
-//
-/// Returns null when the value is 0.
-as_value
-textfield_maxChars(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs)
-    {
-        boost::int32_t maxChars = text->maxChars();
-        if (maxChars == 0)
-        {
-            as_value null;
-            null.set_null();
-            return null;
-        }
-        return as_value(maxChars);
-    }
-    // Setter
-    text->maxChars(toInt(fn.arg(0)));
-    return as_value();
-}
-
-as_value
-textfield_text(const fn_call& fn)
-{
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-    if (!fn.nargs)
-    {
-        // Getter
-        //
-        // FIXME: should return text without HTML tags.
-        return as_value(ptr->get_text_value());
-    }
-
-    // Setter
-    const int version = getSWFVersion(fn);
-    ptr->setTextValue(
-            utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
-
-    return as_value();
-}
-
-as_value
-textfield_htmlText(const fn_call& fn)
-{
-    GNASH_REPORT_FUNCTION;
-
-    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(ptr->get_htmltext_value());
-    }
-
-    // Setter
-    const int version = getSWFVersion(fn);
-    
-    ptr->setHtmlTextValue(
-            utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
-
-    return as_value();
-}
-
-/// TextField.replaceSel(newText)
-//
-/// Replaces the current selection with the new text, setting both
-/// begin and end of the selection to one after the inserted text.
-/// If an empty string is passed, SWF8 erases the selection; SWF7 and below
-/// is a no-op.
-/// If no argument is passed, this is a no-op.
-as_value
-textfield_replaceSel(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if (!fn.nargs) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            std::ostringstream os;
-            fn.dump_args(os);
-            log_aserror("TextField.replaceSel(%s) requires exactly one "
-                "argument", os.str());
-        );
-        return as_value();
-    }
-
-    const std::string& replace = fn.arg(0).to_string();
-
-    /// Do nothing if text is empty and version less than 8.
-    const int version = getSWFVersion(fn);
-    if (version < 8 && replace.empty()) return as_value();
-
-    text->replaceSelection(replace);
-
-    return as_value();
-}
-
-as_value
-textfield_scroll(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-    UNUSED(text);
-
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(1 + text->getScroll());
-    }
-    // Setter
-    text->setScroll(int(fn.arg(0).to_number()) - 1); 
-
-    return as_value();
-}
-
-as_value
-textfield_hscroll(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    LOG_ONCE(log_unimpl("TextField._hscroll is not complete"));
-
-    if (!fn.nargs)
-    {
-        // Getter
-        return as_value(text->getHScroll());
-    }
-    // Setter
-    text->setHScroll(int(fn.arg(0).to_number()));
-
-    return as_value();
-}
-
-as_value
-textfield_maxscroll(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    LOG_ONCE(log_unimpl("TextField.maxscroll is not complete"));
-
-    if (!fn.nargs) {
-        // Getter
-        return as_value(text->getMaxScroll());
-    }
-
-    return as_value();
-}
-
-as_value
-textfield_replaceText(const fn_call& fn)
-{
-    using std::string;
-    using std::wstring;
-
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    if ( fn.nargs < 3 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("TextField.replaceText() called with less than 3 args"));
-        )
-        return as_value();
-    }
-
-    int userEnd = toInt(fn.arg(1));
-    if ( userEnd < 0 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("TextField.replaceText(%s): negative endIndex"
-            " - doing nothing", ss.str());
-        );
-        return as_value();
-    }
-
-    wstring::size_type start = toInt(fn.arg(0));
-    wstring::size_type end = userEnd;
-
-    int version = getSWFVersion(fn);
-
-    // TODO: check if it's possible for SWF6 to use this function
-    //       and if it is whether to_string should be to_string
-    //       (affects the way undefined values are considered)
-    const wstring& replacement =
-        utf8::decodeCanonicalString(fn.arg(2).to_string(), version);
-
-    // TODO: drop this round uf8 encoding and decoding by exposing
-    //       a TextField::getTextValue ?
-    const wstring& subject =
-        utf8::decodeCanonicalString(text->get_text_value(), version);
-
-    if ( start > subject.length() )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("TextField.replaceText(%s): beginIndex out of range"
-            " - doing nothing", ss.str());
-        );
-        return as_value();
-    }
-
-
-    // TODO: use STL proper
-    wstring newstring;
-    if ( start ) newstring = subject.substr(0, start);
-    newstring.append(replacement);
-
-    if ( end > subject.length() )
-    {
-        //log_aserror...
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("TextField.replaceText(%s): endIndex out of range"
-            " - taking as end of string", ss.str());
-        );
-    }
-    else
-    {
-        newstring.append(subject.substr(end));
-    }
-
-    // TODO: check if we should really be updating registered variables
-    text->setTextValue(newstring);
-
-    return as_value();
-}
-
-as_value
-textfield_removeTextField(const fn_call& fn)
-{
-    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
-
-    text->removeTextField();
-
-    LOG_ONCE(log_debug("TextField.removeTextField() TESTING"));
-
-    return as_value();
-}
-
-
-/// This is called for 'new TextField()'
-//
-/// Note that MovieClip.createTextField must call this function (or anything
-/// that replaces it).
-//
-/// Tests in actionscript.all/TextField.as show that this constructor:
-///     1. Adds properties to the prototype.
-///     2. Removes array typing.
-///     3. Removes any Relay.
-///     4. Does not produce a DisplayObject.
-///     5. Operates on a 'this' pointer that createTextField turns into a
-///        real TextField.
-as_value
-textfield_ctor(const fn_call& fn)
-{
-
-    if (isAS3(fn)) {
-        as_object* obj = ensure<ValidThis>(fn);
-        SWFRect nullRect;
-        obj->setDisplayObject(new TextField(obj, 0, nullRect));
-        return as_value();
-    }
-
-    as_object* obj = ensure<ValidThis>(fn);
-    
-    // It's not clear why this happens. Attaching a relay would have the
-    // same effect as both following statements.
-    obj->setArray(false);
-    obj->setRelay(0);
-
-    as_object* proto = obj->get_prototype();
-
-    if (proto) {
-        attachPrototypeProperties(*proto);
-    }
-
-    as_object* ar = getGlobal(fn).createArray();
-    callMethod(ar, NSV::PROP_PUSH, obj);
-    obj->set_member(NSV::PROP_uLISTENERS, ar);
-    return as_value();
-}
-
-
-void
-attachTextFieldInterface(as_object& o)
-{
-    // SWF6 or higher
-    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
-
-    VM& vm = getVM(o);
-    o.init_member("replaceSel", vm.getNative(104, 100), swf6Flags);
-    o.init_member("getTextFormat", vm.getNative(104, 101), swf6Flags);
-    o.init_member("setTextFormat", vm.getNative(104, 102), swf6Flags);
-    o.init_member("removeTextField", vm.getNative(104, 103), swf6Flags);
-    o.init_member("getNewTextFormat", vm.getNative(104, 104), swf6Flags);
-    o.init_member("setNewTextFormat",vm.getNative(104, 105), swf6Flags);
-    o.init_member("getDepth", vm.getNative(104, 106), swf6Flags);
-
-    // SWF7 or higher
-    const int swf7Flags = as_object::DefaultFlags | PropFlags::onlySWF7Up;
-
-    o.init_member("replaceText",vm.getNative(104, 107), swf7Flags);
-    
-    // TextField is an AsBroadcaster
-    AsBroadcaster::initialize(o);
-
-    // Finally ASSetPropFlags is called on the prototype.
-    Global_as& gl = getGlobal(o);
-    as_object* null = 0;
-    callMethod(&gl, NSV::PROP_AS_SET_PROP_FLAGS, &o, null, 131);
-}
-
-void
-attachTextFieldStaticMembers(as_object& o)
-{
-    // SWF6 or higher
-    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
-    VM& vm = getVM(o);
-    o.init_member("getFontList", vm.getNative(104, 201), swf6Flags);
-}
-
-
-/// Return autoSize value as a string
-//
-/// @param val      AutoSize value 
-/// @return         a C-string representation of the autoSize value.
-///                    The return is *never* NULL.
-const char*
-autoSizeValueName(TextField::AutoSize val)
-{
-    switch (val) {
-        case TextField::AUTOSIZE_LEFT:
-            return "left";
-        case TextField::AUTOSIZE_RIGHT:
-            return "right";
-        case TextField::AUTOSIZE_CENTER:
-            return "center";
-        case TextField::AUTOSIZE_NONE:
-        default:
-            return "none";
-    }
-
-}
-
-TextField::AutoSize
-parseAutoSize(const std::string& val)
-{
-    StringNoCaseEqual cmp;
-
-    if (cmp(val, "left")) {
-        return TextField::AUTOSIZE_LEFT;
-    }
-    if (cmp(val, "right")) {
-        return TextField::AUTOSIZE_RIGHT;
-    }
-    if (cmp(val, "center")) {
-        return TextField::AUTOSIZE_CENTER;
-    }
-    return TextField::AUTOSIZE_NONE;
-}
-
-
-} // anonymous namespace
 
 } // namespace gnash
 

=== modified file 'libcore/TextField.h'
--- a/libcore/TextField.h       2010-01-25 11:13:55 +0000
+++ b/libcore/TextField.h       2010-02-15 14:55:30 +0000
@@ -838,16 +838,6 @@
        
 };
 
-/// Native function to create a plain object with TextField properties
-//
-/// This function calls the TextField constructor.
-as_object* createTextFieldObject(Global_as& gl);
-
-/// Initialize the global TextField class
-void textfield_class_init(as_object& global, const ObjectURI& uri);
-
-void registerTextFieldNative(as_object& global);
-
 } // namespace gnash
 
 #endif 

=== modified file 'libcore/asobj/Globals.cpp'
--- a/libcore/asobj/Globals.cpp 2010-01-11 06:41:38 +0000
+++ b/libcore/asobj/Globals.cpp 2010-02-15 14:55:30 +0000
@@ -67,6 +67,7 @@
 #include "flash/net/NetStream_as.h"
 #include "flash/system/System_as.h"
 #include "flash/text/TextSnapshot_as.h"
+#include "flash/text/TextField_as.h"
 #include "flash/text/TextFieldAutoSize_as.h"
 #include "flash/text/Font_as.h"
 #include "flash/text/FontStyle_as.h"
@@ -92,7 +93,6 @@
 #include "Timers.h"
 #include "URL.h" 
 #include "builtin_function.h"
-#include "TextField.h"
 #include "rc.h"
 #include "ClassHierarchy.h"
 #include "namedStrings.h"

=== modified file 'libcore/asobj/flash/text/TextField_as.cpp'
--- a/libcore/asobj/flash/text/TextField_as.cpp 2010-01-25 18:52:20 +0000
+++ b/libcore/asobj/flash/text/TextField_as.cpp 2010-02-15 14:55:30 +0000
@@ -19,269 +19,1179 @@
 
 
 #include "text/TextField_as.h"
+#include "TextField.h"
 #include "log.h"
 #include "fn_call.h"
 #include "Global_as.h"
 #include "smart_ptr.h" // for boost intrusive_ptr
 #include "builtin_function.h" // need builtin_function
-#include "GnashException.h" // for ActionException
+#include "AsBroadcaster.h" // for initializing self as a broadcaster
+#include "flash/text/TextFormat_as.h"
+#include "MovieClip.h"
+#include "NativeFunction.h"
+#include "GnashNumeric.h"
+#include "Movie.h"
+#include "fontlib.h"
+#include "utf8.h"
 
 namespace gnash {
 
 // Forward declarations
 namespace {
-    as_value textfield_getCharBoundaries(const fn_call& fn);
-    as_value textfield_getCharIndexAtPoint(const fn_call& fn);
-    as_value textfield_getFirstCharInParagraph(const fn_call& fn);
-    as_value textfield_getImageReference(const fn_call& fn);
-    as_value textfield_getLineIndexAtPoint(const fn_call& fn);
-    as_value textfield_getLineIndexOfChar(const fn_call& fn);
-    as_value textfield_getLineLength(const fn_call& fn);
-    as_value textfield_getLineMetrics(const fn_call& fn);
-    as_value textfield_getLineOffset(const fn_call& fn);
-    as_value textfield_getLineText(const fn_call& fn);
-    as_value textfield_getParagraphLength(const fn_call& fn);
+    const char* autoSizeValueName(TextField::AutoSize val);
+    TextField::AutoSize parseAutoSize(const std::string& val);
+
+    void attachPrototypeProperties(as_object& proto);
+    void attachTextFieldStaticMembers(as_object& o);
+    void attachTextFieldInterface(as_object& o);
+
+    as_value textfield_createTextField(const fn_call& fn);
+    
+    as_value textfield_variable(const fn_call& fn);
+    as_value textfield_setTextFormat(const fn_call& fn);
     as_value textfield_getTextFormat(const fn_call& fn);
-    as_value textfield_replaceSelectedText(const fn_call& fn);
+    as_value textfield_setNewTextFormat(const fn_call& fn);
+    as_value textfield_getNewTextFormat(const fn_call& fn);
+    as_value textfield_getDepth(const fn_call& fn);
+    as_value textfield_getFontList(const fn_call& fn);
+    as_value textfield_removeTextField(const fn_call& fn);
+    as_value textfield_replaceSel(const fn_call& fn);
     as_value textfield_replaceText(const fn_call& fn);
-    as_value textfield_setSelection(const fn_call& fn);
-    as_value textfield_setTextFormat(const fn_call& fn);
-    as_value textfield_change(const fn_call& fn);
-    as_value textfield_link(const fn_call& fn);
+    as_value textfield_password(const fn_call& fn);
+    as_value textfield_ctor(const fn_call& fn);
+    as_value textfield_multiline(const fn_call& fn);
     as_value textfield_scroll(const fn_call& fn);
-    as_value textfield_textInput(const fn_call& fn);
-    as_value textfield_ctor(const fn_call& fn);
-    void attachTextFieldInterface(as_object& o);
-    void attachTextFieldStaticInterface(as_object& o);
-}
-
-// extern (used by Global.cpp)
+    as_value textfield_maxscroll(const fn_call& fn);
+    as_value textfield_maxhscroll(const fn_call& fn);
+    as_value textfield_maxChars(const fn_call& fn);
+    as_value textfield_bottomScroll(const fn_call& fn);
+    as_value textfield_hscroll(const fn_call& fn);
+    as_value textfield_htmlText(const fn_call& fn);
+    as_value textfield_restrict(const fn_call& fn);
+    as_value textfield_background(const fn_call& fn);
+    as_value textfield_border(const fn_call& fn);
+    as_value textfield_backgroundColor(const fn_call& fn);
+    as_value textfield_borderColor(const fn_call& fn);
+    as_value textfield_text(const fn_call& fn);
+    as_value textfield_textColor(const fn_call& fn);
+    as_value textfield_embedFonts(const fn_call& fn);
+    as_value textfield_autoSize(const fn_call& fn);
+    as_value textfield_type(const fn_call& fn);
+    as_value textfield_wordWrap(const fn_call& fn);
+    as_value textfield_html(const fn_call& fn);
+    as_value textfield_selectable(const fn_call& fn);
+    as_value textfield_length(const fn_call& fn);
+    as_value textfield_textWidth(const fn_call& fn);
+    as_value textfield_textHeight(const fn_call& fn);
+}
+
+as_object*
+createTextFieldObject(Global_as& gl)
+{
+    as_value tf(gl.getMember(NSV::CLASS_TEXT_FIELD));
+    as_function* ctor = tf.to_function();
+    if (!ctor) return 0;
+    fn_call::Args args;
+    as_environment env(getVM(gl));
+    return constructInstance(*ctor, env, args);
+}
+
+/// This provides the prototype and static methods for TextField.
+//
+/// For SWF5 there is initially no prototype, for SWF6+ there is a 
+/// limited prototype. This is changed later on instantiation of a
+/// TextField.
 void
 textfield_class_init(as_object& where, const ObjectURI& uri)
 {
-    registerBuiltinClass(where, textfield_ctor, attachTextFieldInterface, 
-        attachTextFieldStaticInterface, uri);
-}
+
+    Global_as& gl = getGlobal(where);
+    as_object* proto = gl.createObject();
+    as_object* cl = gl.createClass(&textfield_ctor, proto);
+
+    attachTextFieldInterface(*proto);
+    attachTextFieldStaticMembers(*cl);
+             
+    where.init_member(uri, cl, as_object::DefaultFlags);
+
+    // ASSetPropFlags is called on the TextField class.
+    as_object* null = 0;
+    callMethod(&gl, NSV::PROP_AS_SET_PROP_FLAGS, cl, null, 131);
+}
+
+void
+registerTextFieldNative(as_object& global)
+{
+    VM& vm = getVM(global);
+    vm.registerNative(textfield_replaceSel, 104, 100);
+    vm.registerNative(textfield_getTextFormat, 104, 101);
+    vm.registerNative(textfield_setTextFormat, 104, 102);
+    vm.registerNative(textfield_removeTextField, 104, 103);
+    vm.registerNative(textfield_getNewTextFormat, 104, 104);
+    vm.registerNative(textfield_setNewTextFormat, 104, 105);
+    vm.registerNative(textfield_getDepth, 104, 106);
+    vm.registerNative(textfield_replaceText, 104, 107);
+
+    vm.registerNative(textfield_createTextField, 104, 200);
+    vm.registerNative(textfield_getFontList, 104, 201);
+}
+
 
 namespace {
 
 void
-attachTextFieldInterface(as_object& o)
-{
-    o.init_member("getCharBoundaries", 
gl.createFunction(textfield_getCharBoundaries));
-    o.init_member("getCharIndexAtPoint", 
gl.createFunction(textfield_getCharIndexAtPoint));
-    o.init_member("getFirstCharInParagraph", 
gl.createFunction(textfield_getFirstCharInParagraph));
-    o.init_member("getImageReference", 
gl.createFunction(textfield_getImageReference));
-    o.init_member("getLineIndexAtPoint", 
gl.createFunction(textfield_getLineIndexAtPoint));
-    o.init_member("getLineIndexOfChar", 
gl.createFunction(textfield_getLineIndexOfChar));
-    o.init_member("getLineLength", gl.createFunction(textfield_getLineLength));
-    o.init_member("getLineMetrics", 
gl.createFunction(textfield_getLineMetrics));
-    o.init_member("getLineOffset", gl.createFunction(textfield_getLineOffset));
-    o.init_member("getLineText", gl.createFunction(textfield_getLineText));
-    o.init_member("getParagraphLength", 
gl.createFunction(textfield_getParagraphLength));
-    o.init_member("getTextFormat", gl.createFunction(textfield_getTextFormat));
-    o.init_member("replaceSelectedText", 
gl.createFunction(textfield_replaceSelectedText));
-    o.init_member("replaceText", gl.createFunction(textfield_replaceText));
-    o.init_member("setSelection", gl.createFunction(textfield_setSelection));
-    o.init_member("setTextFormat", gl.createFunction(textfield_setTextFormat));
-    o.init_member("change", gl.createFunction(textfield_change));
-    o.init_member("link", gl.createFunction(textfield_link));
-    o.init_member("scroll", gl.createFunction(textfield_scroll));
-    o.init_member("textInput", gl.createFunction(textfield_textInput));
-}
-
-void
-attachTextFieldStaticInterface(as_object& o)
-{
-}
-
-as_value
-textfield_getCharBoundaries(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getCharIndexAtPoint(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getFirstCharInParagraph(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getImageReference(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineIndexAtPoint(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineIndexOfChar(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineLength(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineMetrics(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineOffset(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getLineText(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_getParagraphLength(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
+attachPrototypeProperties(as_object& o)
+{
+    // SWF6 or higher
+    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
+
+    boost::intrusive_ptr<builtin_function> getset;
+
+    // The following properties should only be attached to the prototype
+    // on first textfield creation.
+    o.init_property(NSV::PROP_TEXT_WIDTH,
+            textfield_textWidth, textfield_textWidth);
+    o.init_property(NSV::PROP_TEXT_HEIGHT,
+            textfield_textHeight, textfield_textHeight);
+
+    Global_as& gl = getGlobal(o);
+
+    getset = gl.createFunction(textfield_variable);
+    o.init_property("variable", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_background);
+    o.init_property("background", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_text);
+    o.init_property("text", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_backgroundColor);
+    o.init_property("backgroundColor", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_border);
+    o.init_property("border", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_borderColor);
+    o.init_property("borderColor", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_textColor);
+    o.init_property("textColor", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_embedFonts);
+    o.init_property("embedFonts", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_autoSize);
+    o.init_property("autoSize", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_type);
+    o.init_property("type", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_wordWrap);
+    o.init_property("wordWrap", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_html);
+    o.init_property("html", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_selectable);
+    o.init_property("selectable", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_length);
+    o.init_property("length", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_maxscroll);
+    o.init_property("maxscroll", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_maxhscroll);
+    o.init_property("maxhscroll", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_maxChars);
+    o.init_property("maxChars", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_bottomScroll);
+    o.init_property("bottomScroll", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_scroll);
+    o.init_property("scroll", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_hscroll);
+    o.init_property("hscroll", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_restrict);
+    o.init_property("restrict", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_multiline);
+    o.init_property("multiline", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_password);
+    o.init_property("password", *getset, *getset, swf6Flags);
+    getset = gl.createFunction(textfield_htmlText);
+    o.init_property("htmlText", *getset, *getset, swf6Flags);
+}
+
+
+/// This is in fact a property of MovieClip, but it is more a TextField
+/// function, as its major number (104) in the native table shows.
+as_value
+textfield_createTextField(const fn_call& fn)
+{
+    MovieClip* ptr = ensure<IsDisplayObject<MovieClip> >(fn);
+    
+    // name, depth, x, y, width, height
+    if (fn.nargs < 6) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField called with %d args, "
+            "expected 6 - returning undefined"), fn.nargs);
+        );
+        return as_value();
+    }
+
+    const std::string& name = fn.arg(0).to_string();
+    const int depth = toInt(fn.arg(1));
+    const int x = toInt(fn.arg(2));
+    const int y = toInt(fn.arg(3));
+    
+    int width = toInt(fn.arg(4));
+    if (width < 0) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField: negative width (%d)"
+            " - reverting sign"), width);
+        );
+        width = -width;
+    }
+
+    int height = toInt(fn.arg(5));
+    if ( height < 0 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField: negative height (%d)"
+            " - reverting sign"), height);
+        );
+        height = -height;
+    }
+    // Set textfield bounds
+    SWFRect bounds(0, 0, pixelsToTwips(width), pixelsToTwips(height));
+
+    // Tests in actionscript.all/TextField.as show that this function must:
+    //  1. Call "new _global.TextField()" (which takes care of
+    //     assigning properties to the prototype).
+    //  2. Make that object into a TextField and put it on the display list.
+    as_object* obj = createTextFieldObject(getGlobal(fn));
+
+    DisplayObject* tf = new TextField(obj, ptr, bounds);
+
+    // Give name and mark as dynamic
+    tf->set_name(name);
+    tf->setDynamic();
+
+    // Set _x and _y
+    SWFMatrix matrix;
+    matrix.set_translation(pixelsToTwips(x), pixelsToTwips(y));
+    // update caches (although shouldn't be needed as we only set translation)
+    tf->setMatrix(matrix, true); 
+
+    ptr->addDisplayListObject(tf, depth);
+
+    if (getSWFVersion(fn) > 7) return as_value(obj);
+    return as_value(); 
+}
+
+as_value
+textfield_background(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->getDrawBackground());
+    }
+    else {
+        ptr->setDrawBackground(fn.arg(0).to_bool());
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_border(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->getDrawBorder());
+    }
+    else {
+        ptr->setDrawBorder(fn.arg(0).to_bool());
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_backgroundColor(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->getBackgroundColor().toRGB());
+    }
+    else {
+        rgba newColor;
+        newColor.parseRGB(static_cast<boost::uint32_t>(toInt(fn.arg(0))));
+        ptr->setBackgroundColor(newColor);
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_borderColor(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->getBorderColor().toRGB());
+    }
+    else {
+        rgba newColor;
+        newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_number()));
+        ptr->setBorderColor(newColor);
+    }
+
+    return as_value();
+}
+
+    
+as_value
+textfield_textColor(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        // Getter
+        return as_value(ptr->getTextColor().toRGB());
+    }
+
+    // Setter
+    rgba newColor;
+    newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_number()));
+    ptr->setTextColor(newColor);
+
+    return as_value();
+}
+
+as_value
+textfield_embedFonts(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        // Getter
+        return as_value(ptr->getEmbedFonts());
+    }
+
+    // Setter
+    ptr->setEmbedFonts(fn.arg(0).to_bool());
+    return as_value();
+}
+
+as_value
+textfield_wordWrap(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->doWordWrap());
+    }
+    else {
+        ptr->setWordWrap(fn.arg(0).to_bool());
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_html(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (fn.nargs == 0) {
+        return as_value(ptr->doHtml());
+    }
+    else {
+        ptr->setHtml( fn.arg(0).to_bool() );
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_selectable(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        return as_value(ptr->isSelectable());
+    }
+    else // setter
+    {
+        ptr->setSelectable( fn.arg(0).to_bool() );
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_length(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        const std::string& s = ptr->get_text_value();
+        return as_value(s.length()); // TOCHECK: utf-8 ?
+    }
+    else // setter
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("Attempt to set length property of TextField %s"),
+            ptr->getTarget());
+        );
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_textHeight(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        // Return the height, in pixels, of the text as laid out.
+        // (I.e. the actual text content, not our defined
+        // bounding box.)
+        //
+        // In local coords.  Verified against Macromedia Flash.
+        return as_value(twipsToPixels(ptr->getTextBoundingBox().height()));
+
+    }
+    else // setter
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("Attempt to set read-only %s property of TextField "
+                "%s"), "textHeight", ptr->getTarget());
+        );
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_textWidth(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        // Return the width, in pixels, of the text as laid out.
+        // (I.e. the actual text content, not our defined
+        // bounding box.)
+        //
+        // In local coords.  Verified against Macromedia Flash.
+        return as_value(twipsToPixels(ptr->getTextBoundingBox().width()));
+
+    }
+    else // setter
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("Attempt to set read-only %s property of TextField %s"),
+            "textWidth", ptr->getTarget());
+        );
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_autoSize(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        return autoSizeValueName(ptr->getAutoSize());
+    }
+    else // setter
+    {
+        const as_value& arg = fn.arg(0);
+        if (arg.is_bool()) {
+            if (arg.to_bool()) {
+                // True equates to left, every other bool to none.
+                ptr->setAutoSize(TextField::AUTOSIZE_LEFT);
+            }
+            else {
+                ptr->setAutoSize(TextField::AUTOSIZE_NONE);
+            }
+        }
+        else {
+            std::string strval = arg.to_string();
+            TextField::AutoSize val = parseAutoSize(strval);
+            ptr->setAutoSize(val);
+        }
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_type(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        // getter
+        return ptr->typeValueName(ptr->getType());
+    }
+
+    // setter
+    const as_value& arg = fn.arg(0);
+    std::string strval = arg.to_string();
+    TextField::TypeValue val = ptr->parseTypeValue(strval);
+
+    IF_VERBOSE_ASCODING_ERRORS(
+        if (val == TextField::typeInvalid) {
+            log_aserror(_("Invalid value given to TextField.type: %s"), 
strval);
+        }
+    );
+    ptr->setType(val);
+    return as_value();
+}
+
+
+as_value
+textfield_variable(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs)
+    {
+        // Getter
+        const std::string& varName = text->getVariableName();
+        // An empty variable name returns null.
+        if (varName.empty()) {
+            as_value null;
+            null.set_null();
+            return null;
+        }
+        return as_value(varName);
+    }
+
+    // Setter
+    const as_value& varName = fn.arg(0);
+    if (varName.is_undefined() || varName.is_null()) {
+        text->set_variable_name("");
+    }
+    else text->set_variable_name(varName.to_string());
+
+    return as_value();
+
+}
+
+
+as_value
+textfield_getDepth(const fn_call& fn)
+{
+    // Unlike MovieClip.getDepth this works only for TextFields.
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    const int n = text->get_depth();
+    return as_value(n);
+}
+
+as_value
+textfield_getFontList(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+    LOG_ONCE(log_unimpl("TextField.getFontList()"));
+
+    return as_value();
+}
+
+as_value
+textfield_getNewTextFormat(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+    LOG_ONCE(log_unimpl("TextField.getNewTextFormat()"));
+
+    return as_value();
+}
+
+
+// This is a bit of a messy compromise. We call the TextFormat ctor (this
+// is necessary because prototype properties are not attached until that is
+// done). Then we access the relay object directly. This is because there
+// aren't enough known parameters to the TextFormat constructor to handle
+// all the values, and it isn't tested properly.
 as_value
 textfield_getTextFormat(const fn_call& fn)
 {
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_replaceSelectedText(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_replaceText(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_setSelection(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    Global_as& gl = getGlobal(fn);
+    as_function* ctor = gl.getMember(NSV::CLASS_TEXT_FORMAT).to_function();
+
+    if (!ctor) return as_value();
+
+    fn_call::Args args;
+    as_object* textformat = constructInstance(*ctor, fn.env(), args);
+    TextFormat_as* tf;
+
+    if (!isNativeType(textformat, tf)) {
+        return as_value();
+    }
+
+    tf->alignSet(text->getTextAlignment());
+    tf->sizeSet(text->getFontHeight());
+    tf->indentSet(text->getIndent());
+    tf->blockIndentSet(text->getBlockIndent());
+    tf->leadingSet(text->getLeading());
+    tf->leftMarginSet(text->getLeftMargin());
+    tf->rightMarginSet(text->getRightMargin());
+    tf->colorSet(text->getTextColor());
+    tf->underlinedSet(text->getUnderlined());
+
+    const Font* font = text->getFont();
+    if (font)
+    {
+        tf->fontSet(font->name());
+        tf->italicSet(font->isItalic());
+        tf->boldSet(font->isBold());
+    }
+
+    // TODO: add font color and some more
+
+    LOG_ONCE(
+        log_unimpl("TextField.getTextFormat() discards url, target, "
+            "tabStops, bullet and display")
+    );
+
+    return as_value(textformat);
 }
 
 as_value
 textfield_setTextFormat(const fn_call& fn)
 {
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_change(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_link(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
+
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( ! fn.nargs )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("TextField.setTextFormat(%s) : %s", ss.str(),
+            _("missing arg"))
+        );
+        return as_value();
+    }
+    else if ( fn.nargs > 2 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_debug("TextField.setTextFormat(%s) : args past the first are "
+                "unhandled by Gnash", ss.str());
+    }
+
+    TextFormat_as* tf;
+    if (!isNativeType(fn.arg(0).to_object(getGlobal(fn)), tf)) {
+
+        IF_VERBOSE_ASCODING_ERRORS(
+            std::stringstream ss; fn.dump_args(ss);
+            log_aserror("TextField.setTextFormat(%s) : %s", ss.str(), 
+                _("first argument is not a TextFormat"))
+            );
+        return as_value();
+    }
+
+    if (isAS3(fn)) {
+        // TODO: current font finding assumes we have a parent, which isn't
+        // necessarily the case in AS3. It seems the AS2 implementation is
+        // wrong anyway.
+        log_unimpl("fonts in AS3 TextField.setTextFormat");
+        return as_value();
+    }
+
+    if (tf->font())
+    {
+        const std::string& fontName = *tf->font();
+        if ( ! fontName.empty() )
+        {
+            bool bold = tf->bold() ? *tf->bold() : false;
+            bool italic = tf->italic() ? *tf->italic() : false;
+
+            // NOTE: should query movie-private font lib, not global-shared one
+            Movie* mi = text->get_root();
+            assert(mi);
+            const movie_definition* md = mi->definition();
+            assert(md);
+            Font* f = md->get_font(fontName, bold, italic);
+            if ( ! f ) f = fontlib::get_font(fontName, bold, italic);
+            text->setFont( f );
+        }
+    }
+
+    // TODO: add font color and some more
+    text->setTextFormat(*tf);
+    return as_value();
+
+}
+
+as_value
+textfield_setNewTextFormat(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+    LOG_ONCE( log_unimpl("TextField.setNewTextFormat(), we'll delegate "
+                "to setTextFormat") );
+    return textfield_setTextFormat(fn);
+}
+
+as_value
+textfield_password(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(text->password());
+    }
+    // Setter
+    text->password(fn.arg(0).to_bool());
+    return as_value();
+}
+
+as_value
+textfield_multiline(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        // Getter
+        return as_value(text->multiline());
+    }
+    // Setter
+    text->multiline(fn.arg(0).to_bool());
+    return as_value();
+}
+
+as_value
+textfield_restrict(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        // Getter
+        if (text->isRestrict()) {
+            return as_value(text->getRestrict());
+        } else {
+            as_value null;
+            null.set_null();
+            return null;
+        }
+    }
+    // Setter
+    text->setRestrict(fn.arg(0).to_string());
+    return as_value();
+}
+
+as_value
+textfield_bottomScroll(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+    LOG_ONCE(log_unimpl("TextField.bottomScroll is not complete"));
+
+
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(1 + text->getBottomScroll());
+    }
+    // Setter
+    //text->setBottomScroll(int(fn.arg(0).to_number())); READ-ONLY
+
+    return as_value();
+}
+
+as_value
+textfield_maxhscroll(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+        LOG_ONCE(log_unimpl("TextField.maxhscroll is not complete"));
+
+
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(text->getMaxHScroll());
+    }
+    // Setter
+    //text->setMaxHScroll(int(fn.arg(0).to_number())); READ-ONLY
+
+    return as_value();
+}
+
+/// TextField.maxChars().
+//
+/// This does not limit the length of the text, but rather the
+/// number of DisplayObjects that can be entered in the TextField.
+//
+/// Returns null when the value is 0.
+as_value
+textfield_maxChars(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs)
+    {
+        boost::int32_t maxChars = text->maxChars();
+        if (maxChars == 0)
+        {
+            as_value null;
+            null.set_null();
+            return null;
+        }
+        return as_value(maxChars);
+    }
+    // Setter
+    text->maxChars(toInt(fn.arg(0)));
+    return as_value();
+}
+
+as_value
+textfield_text(const fn_call& fn)
+{
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+    if (!fn.nargs)
+    {
+        // Getter
+        //
+        // FIXME: should return text without HTML tags.
+        return as_value(ptr->get_text_value());
+    }
+
+    // Setter
+    const int version = getSWFVersion(fn);
+    ptr->setTextValue(
+            utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
+
+    return as_value();
+}
+
+as_value
+textfield_htmlText(const fn_call& fn)
+{
+    GNASH_REPORT_FUNCTION;
+
+    TextField* ptr = ensure<IsDisplayObject<TextField> >(fn);
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(ptr->get_htmltext_value());
+    }
+
+    // Setter
+    const int version = getSWFVersion(fn);
+    
+    ptr->setHtmlTextValue(
+            utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
+
+    return as_value();
+}
+
+/// TextField.replaceSel(newText)
+//
+/// Replaces the current selection with the new text, setting both
+/// begin and end of the selection to one after the inserted text.
+/// If an empty string is passed, SWF8 erases the selection; SWF7 and below
+/// is a no-op.
+/// If no argument is passed, this is a no-op.
+as_value
+textfield_replaceSel(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if (!fn.nargs) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            std::ostringstream os;
+            fn.dump_args(os);
+            log_aserror("TextField.replaceSel(%s) requires exactly one "
+                "argument", os.str());
+        );
+        return as_value();
+    }
+
+    const std::string& replace = fn.arg(0).to_string();
+
+    /// Do nothing if text is empty and version less than 8.
+    const int version = getSWFVersion(fn);
+    if (version < 8 && replace.empty()) return as_value();
+
+    text->replaceSelection(replace);
+
     return as_value();
 }
 
 as_value
 textfield_scroll(const fn_call& fn)
 {
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_textInput(const fn_call& fn)
-{
-    as_object* ptr = ensure<ValidThis>(fn);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-textfield_ctor(const fn_call& /*fn*/)
-{
-    return as_value(); 
-}
-
-} // anonymous namespace 
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+    UNUSED(text);
+
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(1 + text->getScroll());
+    }
+    // Setter
+    text->setScroll(int(fn.arg(0).to_number()) - 1); 
+
+    return as_value();
+}
+
+as_value
+textfield_hscroll(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    LOG_ONCE(log_unimpl("TextField._hscroll is not complete"));
+
+    if (!fn.nargs)
+    {
+        // Getter
+        return as_value(text->getHScroll());
+    }
+    // Setter
+    text->setHScroll(int(fn.arg(0).to_number()));
+
+    return as_value();
+}
+
+as_value
+textfield_maxscroll(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    LOG_ONCE(log_unimpl("TextField.maxscroll is not complete"));
+
+    if (!fn.nargs) {
+        // Getter
+        return as_value(text->getMaxScroll());
+    }
+
+    return as_value();
+}
+
+as_value
+textfield_replaceText(const fn_call& fn)
+{
+    using std::string;
+    using std::wstring;
+
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    if ( fn.nargs < 3 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("TextField.replaceText() called with less than 3 args"));
+        )
+        return as_value();
+    }
+
+    int userEnd = toInt(fn.arg(1));
+    if ( userEnd < 0 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("TextField.replaceText(%s): negative endIndex"
+            " - doing nothing", ss.str());
+        );
+        return as_value();
+    }
+
+    wstring::size_type start = toInt(fn.arg(0));
+    wstring::size_type end = userEnd;
+
+    int version = getSWFVersion(fn);
+
+    // TODO: check if it's possible for SWF6 to use this function
+    //       and if it is whether to_string should be to_string
+    //       (affects the way undefined values are considered)
+    const wstring& replacement =
+        utf8::decodeCanonicalString(fn.arg(2).to_string(), version);
+
+    // TODO: drop this round uf8 encoding and decoding by exposing
+    //       a TextField::getTextValue ?
+    const wstring& subject =
+        utf8::decodeCanonicalString(text->get_text_value(), version);
+
+    if ( start > subject.length() )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("TextField.replaceText(%s): beginIndex out of range"
+            " - doing nothing", ss.str());
+        );
+        return as_value();
+    }
+
+
+    // TODO: use STL proper
+    wstring newstring;
+    if ( start ) newstring = subject.substr(0, start);
+    newstring.append(replacement);
+
+    if ( end > subject.length() )
+    {
+        //log_aserror...
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("TextField.replaceText(%s): endIndex out of range"
+            " - taking as end of string", ss.str());
+        );
+    }
+    else
+    {
+        newstring.append(subject.substr(end));
+    }
+
+    // TODO: check if we should really be updating registered variables
+    text->setTextValue(newstring);
+
+    return as_value();
+}
+
+as_value
+textfield_removeTextField(const fn_call& fn)
+{
+    TextField* text = ensure<IsDisplayObject<TextField> >(fn);
+
+    text->removeTextField();
+
+    LOG_ONCE(log_debug("TextField.removeTextField() TESTING"));
+
+    return as_value();
+}
+
+
+/// This is called for 'new TextField()'
+//
+/// Note that MovieClip.createTextField must call this function (or anything
+/// that replaces it).
+//
+/// Tests in actionscript.all/TextField.as show that this constructor:
+///     1. Adds properties to the prototype.
+///     2. Removes array typing.
+///     3. Removes any Relay.
+///     4. Does not produce a DisplayObject.
+///     5. Operates on a 'this' pointer that createTextField turns into a
+///        real TextField.
+as_value
+textfield_ctor(const fn_call& fn)
+{
+
+    if (isAS3(fn)) {
+        as_object* obj = ensure<ValidThis>(fn);
+        SWFRect nullRect;
+        obj->setDisplayObject(new TextField(obj, 0, nullRect));
+        return as_value();
+    }
+
+    as_object* obj = ensure<ValidThis>(fn);
+    
+    // It's not clear why this happens. Attaching a relay would have the
+    // same effect as both following statements.
+    obj->setArray(false);
+    obj->setRelay(0);
+
+    as_object* proto = obj->get_prototype();
+
+    if (proto) {
+        attachPrototypeProperties(*proto);
+    }
+
+    as_object* ar = getGlobal(fn).createArray();
+    callMethod(ar, NSV::PROP_PUSH, obj);
+    obj->set_member(NSV::PROP_uLISTENERS, ar);
+    return as_value();
+}
+
+
+void
+attachTextFieldInterface(as_object& o)
+{
+    // SWF6 or higher
+    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
+
+    VM& vm = getVM(o);
+    o.init_member("replaceSel", vm.getNative(104, 100), swf6Flags);
+    o.init_member("getTextFormat", vm.getNative(104, 101), swf6Flags);
+    o.init_member("setTextFormat", vm.getNative(104, 102), swf6Flags);
+    o.init_member("removeTextField", vm.getNative(104, 103), swf6Flags);
+    o.init_member("getNewTextFormat", vm.getNative(104, 104), swf6Flags);
+    o.init_member("setNewTextFormat",vm.getNative(104, 105), swf6Flags);
+    o.init_member("getDepth", vm.getNative(104, 106), swf6Flags);
+
+    // SWF7 or higher
+    const int swf7Flags = as_object::DefaultFlags | PropFlags::onlySWF7Up;
+
+    o.init_member("replaceText",vm.getNative(104, 107), swf7Flags);
+    
+    // TextField is an AsBroadcaster
+    AsBroadcaster::initialize(o);
+
+    // Finally ASSetPropFlags is called on the prototype.
+    Global_as& gl = getGlobal(o);
+    as_object* null = 0;
+    callMethod(&gl, NSV::PROP_AS_SET_PROP_FLAGS, &o, null, 131);
+}
+
+void
+attachTextFieldStaticMembers(as_object& o)
+{
+    // SWF6 or higher
+    const int swf6Flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
+    VM& vm = getVM(o);
+    o.init_member("getFontList", vm.getNative(104, 201), swf6Flags);
+}
+
+
+/// Return autoSize value as a string
+//
+/// @param val      AutoSize value 
+/// @return         a C-string representation of the autoSize value.
+///                    The return is *never* NULL.
+const char*
+autoSizeValueName(TextField::AutoSize val)
+{
+    switch (val) {
+        case TextField::AUTOSIZE_LEFT:
+            return "left";
+        case TextField::AUTOSIZE_RIGHT:
+            return "right";
+        case TextField::AUTOSIZE_CENTER:
+            return "center";
+        case TextField::AUTOSIZE_NONE:
+        default:
+            return "none";
+    }
+
+}
+
+TextField::AutoSize
+parseAutoSize(const std::string& val)
+{
+    StringNoCaseEqual cmp;
+
+    if (cmp(val, "left")) {
+        return TextField::AUTOSIZE_LEFT;
+    }
+    if (cmp(val, "right")) {
+        return TextField::AUTOSIZE_RIGHT;
+    }
+    if (cmp(val, "center")) {
+        return TextField::AUTOSIZE_CENTER;
+    }
+    return TextField::AUTOSIZE_NONE;
+}
+
+
+} // anonymous namespace
 } // gnash namespace
 
 // local Variables:

=== modified file 'libcore/asobj/flash/text/TextField_as.h'
--- a/libcore/asobj/flash/text/TextField_as.h   2010-01-25 18:52:20 +0000
+++ b/libcore/asobj/flash/text/TextField_as.h   2010-02-15 14:55:30 +0000
@@ -17,23 +17,29 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-#ifndef GNASH_ASOBJ3_TEXTFIELD_H
-#define GNASH_ASOBJ3_TEXTFIELD_H
-
-
-
-namespace gnash {
-
-// Forward declarations
-class as_object;
-class ObjectURI;
+#ifndef GNASH_TEXTFIELD_AS_H
+#define GNASH_TEXTFIELD_AS_H
+
+namespace gnash {
+    class as_object;
+    class ObjectURI;
+    class Global_as;
+}
+
+namespace gnash {
+
+/// Native function to create a plain object with TextField properties
+//
+/// This function calls the TextField constructor.
+as_object* createTextFieldObject(Global_as& gl);
 
 /// Initialize the global TextField class
-void textfield_class_init(as_object& where, const ObjectURI& uri);
-
-} // gnash namespace
-
-// GNASH_ASOBJ3_TEXTFIELD_H
+void textfield_class_init(as_object& global, const ObjectURI& uri);
+
+void registerTextFieldNative(as_object& global);
+
+} // namespace gnash
+
 #endif
 
 // local Variables:

=== modified file 'libcore/asobj/flash/text/text.am'
--- a/libcore/asobj/flash/text/text.am  2010-01-01 17:48:26 +0000
+++ b/libcore/asobj/flash/text/text.am  2010-02-15 14:55:30 +0000
@@ -85,7 +85,7 @@
 
 # FIXME: already exists
 if BUILD_TEXTFIELD_AS3
-# TEXT_SOURCES += asobj/flash/text/TextField_as.cpp
+TEXT_SOURCES += asobj/flash/text/TextField_as.cpp
 TEXT_HEADERS += asobj/flash/text/TextField_as.h
 endif
 

=== modified file 'libcore/swf/DefineEditTextTag.cpp'
--- a/libcore/swf/DefineEditTextTag.cpp 2010-01-01 17:48:26 +0000
+++ b/libcore/swf/DefineEditTextTag.cpp 2010-02-15 14:55:30 +0000
@@ -16,6 +16,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "DefineEditTextTag.h"
+#include "text/TextField_as.h"
 #include "TextField.h"
 #include "movie_definition.h"
 #include "Font.h"
@@ -48,27 +49,6 @@
     as_object* obj = createTextFieldObject(gl);
        TextField* ch = new TextField(obj, parent, *this);
 
-       // This gives an "instance name" to the TextField, but
-       // it is not really what we need.
-       //
-       // First of all the VariableName ("_variableName") is
-       // NOT the default name of an instance, rather it is
-       // a variable associated with it and can contain path
-       // information (ie. we can associate a variable in a different
-       // timeline)
-       //
-       // We actually need to set that variable to an object which
-       // is a TextField dinamic variable. The object should take
-       // care of updating this TextField text when assigned to
-       // and to retrive this TextField text when extracted value from.
-       //
-       // The DefineEditTextVariableNameTest.swf file under
-       // testsuite/misc-ming.all gives an idea of the problem
-       // (in particular it shows a case in which VariableName is
-       // outside of TextField timeline/scope)
-       //
-       //ch->set_name(m_variable_name.c_str());
-
        return ch;
 }
 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]