[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] /srv/bzr/gnash/trunk r11043: Merge from branch
From: |
Bob Naugle |
Subject: |
[Gnash-commit] /srv/bzr/gnash/trunk r11043: Merge from branch |
Date: |
Mon, 08 Jun 2009 16:26:31 -0600 |
User-agent: |
Bazaar (1.13.1) |
------------------------------------------------------------
revno: 11043
committer: Bob Naugle <address@hidden>
branch nick: trunk
timestamp: Mon 2009-06-08 16:26:31 -0600
message:
Merge from branch
removed:
libcore/TextField.cpp
libcore/TextField.h
modified:
libcore/ClassHierarchy.cpp
libcore/Makefile.am
libcore/MovieClip.cpp
libcore/MovieClip.h
libcore/asobj/Global.cpp
libcore/asobj/Selection_as.cpp
libcore/asobj/flash/text/TextField_as.cpp
libcore/asobj/flash/text/TextField_as.h
libcore/asobj/flash/text/TextFormat_as.cpp
libcore/asobj/flash/text/TextFormat_as.h
libcore/asobj/flash/text/text.am
libcore/swf/DefineEditTextTag.cpp
libcore/swf/DefineEditTextTag.h
testsuite/as3/classes.all/text/TextField_as.hx
------------------------------------------------------------
revno: 11042.1.1
committer: Bob Naugle <address@hidden>
branch nick: development
timestamp: Mon 2009-06-08 16:24:55 -0600
message:
Migrated TextField to new file and directory. Modified makefiles,
dependencies, and test cases accordingly.
removed:
libcore/TextField.cpp
libcore/TextField.h
modified:
libcore/ClassHierarchy.cpp
libcore/Makefile.am
libcore/MovieClip.cpp
libcore/MovieClip.h
libcore/asobj/Global.cpp
libcore/asobj/Selection_as.cpp
libcore/asobj/flash/text/TextField_as.cpp
libcore/asobj/flash/text/TextField_as.h
libcore/asobj/flash/text/TextFormat_as.cpp
libcore/asobj/flash/text/TextFormat_as.h
libcore/asobj/flash/text/text.am
libcore/swf/DefineEditTextTag.cpp
libcore/swf/DefineEditTextTag.h
testsuite/as3/classes.all/text/TextField_as.hx
=== modified file 'libcore/ClassHierarchy.cpp'
--- a/libcore/ClassHierarchy.cpp 2009-06-08 22:15:34 +0000
+++ b/libcore/ClassHierarchy.cpp 2009-06-08 22:24:55 +0000
@@ -58,7 +58,7 @@
#include "VM.h"
#include "URL.h" // for URL::encode and URL::decode (escape/unescape)
#include "builtin_function.h"
-#include "TextField.h"
+#include "flash/text/TextField_as.h"
#include "namedStrings.h"
#include "ClassHierarchy.h"
#include "builtin_function.h"
@@ -292,7 +292,7 @@
{ system_class_init, NSV::CLASS_SYSTEM, 0, NSV::NS_FLASH_SYSTEM, 1 },
{ stage_class_init, NSV::CLASS_STAGE, 0, NSV::NS_FLASH_DISPLAY, 1 },
{ movieclip_class_init, NSV::CLASS_MOVIE_CLIP, 0,
NSV::NS_FLASH_DISPLAY, 3 },
- { textfield_class_init, NSV::CLASS_TEXT_FIELD, 0, NSV::NS_FLASH_TEXT, 3
},
+ { TextField_as::init, NSV::CLASS_TEXT_FIELD, 0, NSV::NS_FLASH_TEXT, 3 },
{ math_class_init, NSV::CLASS_MATH, 0, NS_GLOBAL, 4 },
{ boolean_class_init, NSV::CLASS_BOOLEAN, NSV::CLASS_OBJECT, NS_GLOBAL,
5 },
{ Button::init, NSV::CLASS_BUTTON, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am 2009-06-06 23:27:19 +0000
+++ b/libcore/Makefile.am 2009-06-08 22:24:55 +0000
@@ -70,16 +70,15 @@
Shape.cpp \
MorphShape.cpp \
StaticText.cpp \
- TextField.cpp \
- BlurFilter.cpp \
- GlowFilter.cpp \
- DropShadowFilter.cpp \
- ConvolutionFilter.cpp \
- ColorMatrixFilter.cpp \
- GradientGlowFilter.cpp \
- BevelFilter.cpp \
- GradientBevelFilter.cpp \
- parser/filter_factory.cpp \
+ BlurFilter.cpp \
+ GlowFilter.cpp \
+ DropShadowFilter.cpp \
+ ConvolutionFilter.cpp \
+ ColorMatrixFilter.cpp \
+ GradientGlowFilter.cpp \
+ BevelFilter.cpp \
+ GradientBevelFilter.cpp \
+ parser/filter_factory.cpp \
InteractiveObject.cpp \
SWFMatrix.cpp \
SWFMovie.cpp \
@@ -146,17 +145,16 @@
BitmapMovie.h \
Button.h \
debugger.h \
- TextField.h \
- BitmapFilter.h \
- BlurFilter.h \
- BevelFilter.h \
- GradientBevelFilter.h \
- GlowFilter.h \
- GradientGlowFilter.h \
- DropShadowFilter.h \
- ConvolutionFilter.h \
- ColorMatrixFilter.h \
- parser/filter_factory.h \
+ BitmapFilter.h \
+ BlurFilter.h \
+ BevelFilter.h \
+ GradientBevelFilter.h \
+ GlowFilter.h \
+ GradientGlowFilter.h \
+ DropShadowFilter.h \
+ ConvolutionFilter.h \
+ ColorMatrixFilter.h \
+ parser/filter_factory.h \
Font.h \
fontlib.h \
Shape.h \
=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp 2009-06-08 21:40:22 +0000
+++ b/libcore/MovieClip.cpp 2009-06-08 22:24:55 +0000
@@ -28,7 +28,7 @@
#include "as_value.h"
#include "as_function.h"
#include "Bitmap.h"
-#include "TextField.h"
+#include "text/TextField_as.h"
#include "ControlTag.h"
#include "fn_call.h"
#include "flash/ui/Keyboard_as.h"
@@ -638,7 +638,7 @@
for (TextFields::const_iterator i=etc->begin(), e=etc->end();
i!=e; ++i)
{
- boost::intrusive_ptr<TextField> tf = i->get();
+ boost::intrusive_ptr<TextField_as> tf = i->get();
if ( tf->getTextDefined() )
{
val->set_string(tf->get_text_value());
@@ -767,7 +767,7 @@
rect bounds(0, 0, pixelsToTwips(width), pixelsToTwips(height));
// Create an instance
- boost::intrusive_ptr<DisplayObject> txt_char = new TextField(this, bounds);
+ boost::intrusive_ptr<DisplayObject> txt_char = new TextField_as(this,
bounds);
// Give name and mark as dynamic
txt_char->set_name(name);
@@ -1970,7 +1970,7 @@
void
-MovieClip::set_textfield_variable(const std::string& name, TextField* ch)
+MovieClip::set_textfield_variable(const std::string& name, TextField_as* ch)
{
assert(ch);
=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h 2009-06-03 13:34:35 +0000
+++ b/libcore/MovieClip.h 2009-06-08 22:24:55 +0000
@@ -46,7 +46,7 @@
class drag_state;
class LoadVariablesThread;
class gradient_record;
- class TextField;
+ class TextField_as;
class BitmapData_as;
class BitmapInfo;
namespace SWF {
@@ -588,7 +588,7 @@
/// A TextField variable is a variable that acts
/// as a setter/getter for a TextField 'text' member.
///
- void set_textfield_variable(const std::string& name, TextField* ch);
+ void set_textfield_variable(const std::string& name, TextField_as* ch);
void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
@@ -809,7 +809,7 @@
private:
- typedef std::vector<boost::intrusive_ptr<TextField> > TextFields;
+ typedef std::vector<boost::intrusive_ptr<TextField_as> > TextFields;
/// A container for textfields, indexed by their variable name
typedef std::map<std::string, TextFields> TextFieldIndex;
=== removed file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp 2009-06-08 22:15:34 +0000
+++ b/libcore/TextField.cpp 1970-01-01 00:00:00 +0000
@@ -1,2845 +0,0 @@
-// TextField.cpp: User-editable text regions, for Gnash.
-//
-// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-#ifdef HAVE_CONFIG_H
-#include "gnashconfig.h"
-#endif
-
-#include "utf8.h"
-#include "log.h"
-#include "swf/DefineEditTextTag.h"
-#include "render.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 "action.h" // for as_standard_member enum
-#include "VM.h"
-#include "builtin_function.h" // for getter/setter properties
-#include "Font.h" // for using the _font member
-#include "fontlib.h" // for searching or adding fonts the _font member
-#include "Object.h" // for getObjectInterface
-#include "namedStrings.h"
-#include "Array_as.h" // for _listeners construction
-#include "AsBroadcaster.h" // for initializing self as a broadcaster
-#include "StringPredicates.h"
-#include "text/TextFormat_as.h" // for getTextFormat/setTextFormat
-#include "GnashKey.h" // key::code
-#include "TextRecord.h"
-#include "Point2d.h"
-#include "GnashNumeric.h"
-
-#include <algorithm> // std::min
-#include <string>
-#include <boost/algorithm/string/case_conv.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/bind.hpp>
-
-// Text fields have a fixed 2 pixel padding for each side (regardless of
border)
-#define PADDING_TWIPS 40
-
-// Define the following to get detailed log information about
-// textfield bounds and HTML tags:
-//#define GNASH_DEBUG_TEXTFIELDS 1
-
-// Define this to get debugging info about text formatting
-//#define GNASH_DEBUG_TEXT_FORMATTING 1
-
-namespace gnash {
-
-// Forward declarations
-namespace {
- as_object* getTextFieldInterface(VM& vm);
- void attachPrototypeProperties(as_object& proto);
- void attachTextFieldStaticMembers(as_object& o);
-
- 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);
-}
-
-TextField::TextField(DisplayObject* parent, const SWF::DefineEditTextTag& def,
- int id)
- :
- InteractiveObject(parent, id),
- _tag(&def),
- _textDefined(def.hasText()),
- _underlined(false),
- _leading(def.leading()),
- _alignment(def.alignment()),
- _indent(def.indent()),
- _blockIndent(0),
- _leftMargin(def.leftMargin()),
- _rightMargin(def.rightMargin()),
- _fontHeight(def.textHeight()),
- _font(0),
- m_has_focus(false),
- m_cursor(0u),
- m_xcursor(0.0f),
- m_ycursor(0.0f),
- _multiline(def.multiline()),
- _password(def.password()),
- _maxChars(def.maxChars()),
- _text_variable_registered(false),
- _variable_name(def.variableName()),
- _drawBackground(def.border()),
- _backgroundColor(255,255,255,255),
- _drawBorder(def.border()),
- _borderColor(0,0,0,255),
- _textColor(def.color()),
- _embedFonts(def.getUseEmbeddedGlyphs()),
- _wordWrap(def.wordWrap()),
- _html(def.html()),
- _selectable(!def.noSelect()),
- _autoSize(autoSizeNone),
- _type(def.readOnly() ? typeDynamic : typeInput),
- _bounds(def.bounds()),
- _selection(0, 0)
-{
-
- // WARNING! remember to set the font *before* setting text value!
- boost::intrusive_ptr<const Font> f = def.getFont();
- if (!f) f = fontlib::get_default_font();
- setFont(f);
-
- int version = parent->getVM().getSWFVersion();
-
- // set default text *before* calling registerTextVariable
- // (if the textvariable already exist and has a value
- // the text will be replaced with it)
- if (_textDefined)
- {
- setTextValue(utf8::decodeCanonicalString(def.defaultText(), version));
- }
-
- init();
-
-}
-
-TextField::TextField(DisplayObject* parent, const rect& bounds)
- :
- // the id trick is to fool assertions in DisplayObject ctor
- InteractiveObject(parent, parent ? 0 : -1),
- _textDefined(false),
- _underlined(false),
- _leading(0),
- _alignment(ALIGN_LEFT),
- _indent(0),
- _blockIndent(0),
- _leftMargin(0),
- _rightMargin(0),
- _fontHeight(12 * 20),
- _font(0),
- m_has_focus(false),
- m_cursor(0u),
- m_xcursor(0.0f),
- m_ycursor(0.0f),
- _multiline(false),
- _password(false),
- _maxChars(0),
- _text_variable_registered(false),
- _drawBackground(false),
- _backgroundColor(255,255,255,255),
- _drawBorder(false),
- _borderColor(0, 0, 0, 255),
- _textColor(0, 0, 0, 255),
- _embedFonts(false), // ?
- _wordWrap(false),
- _html(false),
- _selectable(true),
- _autoSize(autoSizeNone),
- _type(typeDynamic),
- _bounds(bounds),
- _selection(0, 0)
-{
- // Use the default font (Times New Roman for Windows, Times for Mac
- // according to docs. They don't say what it is for Linux.
- boost::intrusive_ptr<const Font> f = fontlib::get_default_font();
- setFont(f);
-
- init();
-}
-
-void
-TextField::init()
-{
-
- as_object* proto = getTextFieldInterface(_vm);
-
- // This is an instantiation, so attach properties to the
- // prototype.
- // TODO: is it correct to do it here, or can some TextFields
- // be constructed without attaching these?
- attachPrototypeProperties(*proto);
-
- set_prototype(proto);
-
- Array_as* ar = new Array_as();
- ar->push(this);
- set_member(NSV::PROP_uLISTENERS, ar);
-
- registerTextVariable();
-
- reset_bounding_box(0, 0);
-}
-
-
-TextField::~TextField()
-{
-}
-
-void
-TextField::removeTextField()
-{
- int depth = get_depth();
- if ( depth < 0 || depth > 1048575 )
- {
- //IF_VERBOSE_ASCODING_ERRORS(
- log_debug(_("CHECKME: removeTextField(%s): TextField depth (%d) "
- "out of the 'dynamic' zone [0..1048575], won't remove"),
- getTarget(), depth);
- //);
- return;
- }
-
- DisplayObject* parent = get_parent();
- assert(parent); // every TextField must have a parent, right ?
-
- MovieClip* parentSprite = parent->to_movie();
-
- if (!parentSprite)
- {
- log_error("FIXME: attempt to remove a TextField being a child of a %s",
- typeName(*parent));
- return;
- }
-
- // second argument is arbitrary, see comments above
- // the function declaration in MovieClip.h
- parentSprite->remove_display_object(depth, 0);
-}
-
-void
-TextField::show_cursor(const SWFMatrix& mat)
-{
- boost::uint16_t x = static_cast<boost::uint16_t>(m_xcursor);
- boost::uint16_t y = static_cast<boost::uint16_t>(m_ycursor);
- boost::uint16_t h = getFontHeight();
-
- const std::vector<point> box = boost::assign::list_of
- (point(x, y))
- (point(x, y + h));
-
- render::drawLine(box, rgba(0,0,0,255), mat);
-}
-
-void
-TextField::display()
-{
-
- registerTextVariable();
-
- const bool drawBorder = getDrawBorder();
- const bool drawBackground = getDrawBackground();
-
- const SWFMatrix& wmat = getWorldMatrix();
-
- if ((drawBorder || drawBackground) && !_bounds.is_null())
- {
-
- std::vector<point> coords(4);
-
- boost::int32_t xmin = _bounds.get_x_min();
- boost::int32_t xmax = _bounds.get_x_max();
- boost::int32_t ymin = _bounds.get_y_min();
- boost::int32_t ymax = _bounds.get_y_max();
-
- coords[0].setTo(xmin, ymin);
- coords[1].setTo(xmax, ymin);
- coords[2].setTo(xmax, ymax);
- coords[3].setTo(xmin, ymax);
-
- rgba borderColor = drawBorder ? getBorderColor() : rgba(0,0,0,0);
- rgba backgroundColor = drawBackground ? getBackgroundColor() :
- rgba(0,0,0,0);
-
- cxform cx = get_world_cxform();
-
- if (drawBorder) borderColor = cx.transform(borderColor);
-
- if (drawBackground) backgroundColor = cx.transform(backgroundColor);
-
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("rendering a Pol composed by corners %s", _bounds);
-#endif
-
- render::draw_poly(&coords.front(), 4, backgroundColor,
- borderColor, wmat, true);
-
- }
-
- // Draw our actual text.
- // Using a SWFMatrix to translate to def bounds seems an hack to me.
- // A cleaner implementation is likely correctly setting the
- // _xOffset and _yOffset memebers in glyph records.
- // Anyway, see bug #17954 for a testcase.
- SWFMatrix m = getWorldMatrix();
-
- if (!_bounds.is_null()) {
- m.concatenate_translation(_bounds.get_x_min(), _bounds.get_y_min());
- }
-
- SWF::TextRecord::displayRecords(m, get_world_cxform(), _textRecords,
- _embedFonts);
-
- if (m_has_focus) show_cursor(wmat);
-
- clear_invalidated();
-}
-
-
-void
-TextField::add_invalidated_bounds(InvalidatedRanges& ranges,
- bool force)
-{
- if (!force && !m_invalidated) return; // no need to redraw
-
- ranges.add(m_old_invalidated_ranges);
-
- const SWFMatrix& wm = getWorldMatrix();
-
- rect bounds = getBounds();
- bounds.expand_to_rect(m_text_bounding_box);
- wm.transform(bounds);
- ranges.add(bounds.getRange());
-}
-
-void
-TextField::replaceSelection(const std::string& replace)
-{
-
- const int version = _vm.getSWFVersion();
- const std::wstring& wstr = utf8::decodeCanonicalString(replace, version);
-
- const size_t start = _selection.first;
- const size_t replaceLength = wstr.size();
-
- _text.replace(start, _selection.second - start, wstr);
- _selection = std::make_pair(start + replaceLength, start + replaceLength);
-}
-
-void
-TextField::setSelection(int start, int end)
-{
-
- if (_text.empty()) {
- _selection = std::make_pair(0, 0);
- return;
- }
-
- const size_t textLength = _text.size();
-
- if (start < 0) start = 0;
- else start = std::min<size_t>(start, textLength);
-
- if (end < 0) end = 0;
- else end = std::min<size_t>(end, textLength);
-
- // The cursor position is always set to the end value, even if the
- // two values are swapped to obtain the selection. Equal values are
- // fine.
- m_cursor = end;
- if (start > end) std::swap(start, end);
-
- _selection = std::make_pair(start, end);
-}
-bool
-TextField::on_event(const event_id& ev)
-{
- if (isReadOnly()) return false;
-
- switch (ev.id())
- {
- case event_id::KEY_PRESS:
- {
- if ( getType() != typeInput ) break; // not an input field
- std::wstring s = _text;
-
- // id.keyCode is the unique gnash::key::code for a
DisplayObject/key.
- // The maximum value is about 265, including function keys.
- // It seems that typing in DisplayObjects outside the Latin-1 set
- // (256 DisplayObject codes, identical to the first 256 of UTF-8)
- // is not supported, though a much greater number UTF-8 codes can
be
- // stored and displayed. See utf.h for more information.
- // This is a limit on the number of key codes, not on the
- // capacity of strings.
- gnash::key::code c = ev.keyCode();
-
- // maybe _text is changed in ActionScript
- m_cursor = std::min<size_t>(m_cursor, _text.size());
-
- switch (c)
- {
- case key::BACKSPACE:
- if (m_cursor > 0)
- {
- s.erase(m_cursor - 1, 1);
- m_cursor--;
- setTextValue(s);
- }
- break;
-
- case key::DELETEKEY:
- if (s.size() > m_cursor)
- {
- s.erase(m_cursor, 1);
- setTextValue(s);
- }
- break;
-
- case key::INSERT: // TODO
- break;
-
- case key::HOME:
- case key::PGUP:
- case key::UP:
- m_cursor = 0;
- format_text();
- break;
-
- case key::END:
- case key::PGDN:
- case key::DOWN:
- m_cursor = _text.size();
- format_text();
- break;
-
- case key::LEFT:
- m_cursor = m_cursor > 0 ? m_cursor - 1 : 0;
- format_text();
- break;
-
- case key::RIGHT:
- m_cursor = m_cursor < _text.size() ? m_cursor + 1 :
- _text.size();
- format_text();
- break;
-
- default:
- wchar_t t = static_cast<wchar_t>(
- gnash::key::codeMap[c][key::ASCII]);
- if (t != 0)
- {
- // Insert one copy of the DisplayObject
- // at the cursor position.
- s.insert(m_cursor, 1, t);
- m_cursor++;
- }
- setTextValue(s);
- break;
- }
- onChanged();
- }
-
- default:
- return false;
- }
- return true;
-}
-
-InteractiveObject*
-TextField::topmostMouseEntity(boost::int32_t x, boost::int32_t y)
-{
-
- if (!visible()) return 0;
-
- // shouldn't this be !can_handle_mouse_event() instead ?
- // not selectable, so don't catch mouse events!
- if (!_selectable) return 0;
-
- SWFMatrix m = getMatrix();
- point p(x, y);
- m.invert().transform(p);
-
- if (_bounds.point_test(p.x, p.y)) return this;
-
- return 0;
-}
-
-void
-TextField::updateText(const std::string& str)
-{
- int version = _vm.getSWFVersion();
- const std::wstring& wstr = utf8::decodeCanonicalString(str, version);
- updateText(wstr);
-}
-
-void
-TextField::updateText(const std::wstring& wstr)
-{
- _textDefined = true;
-
- if (_text == wstr) return;
-
- set_invalidated();
-
- _text = wstr;
- format_text();
-}
-
-void
-TextField::setTextValue(const std::wstring& wstr)
-{
-
- updateText(wstr);
-
- if ( ! _variable_name.empty() && _text_variable_registered )
- {
- // TODO: notify MovieClip if we have a variable name !
- VariableRef ref = parseTextVariableRef(_variable_name);
- as_object* tgt = ref.first;
- if ( tgt )
- {
- int version = _vm.getSWFVersion();
- // we shouldn't truncate, right?
- tgt->set_member(ref.second, utf8::encodeCanonicalString(wstr,
- version));
- }
- else
- {
- // nothing to do (too early ?)
- log_debug("setTextValue: variable name %s points to a non-existent"
- " target, I guess we would not be registered if this was "
- "true, or the sprite we've registered our variable name "
- "has been unloaded", _variable_name);
- }
- }
-}
-
-std::string
-TextField::get_text_value() const
-{
- // we need the const_cast here because registerTextVariable
- // *might* change our text value, calling the non-const
- // setTextValue().
- // This happens if the TextVariable has not been already registered
- // and during registration comes out to name an existing variable
- // with a pre-existing value.
- const_cast<TextField*>(this)->registerTextVariable();
-
- int version = _vm.getSWFVersion();
-
- return utf8::encodeCanonicalString(_text, version);
-}
-
-bool
-TextField::set_member(string_table::key name,
- const as_value& val, string_table::key nsname, bool ifFound)
-{
-
- // FIXME: Turn all standard members into getter/setter properties
- // of the TextField class. See attachTextFieldInterface()
- // @@ TODO need to inherit basic stuff like _x, _y, _xscale, _yscale etc ?
-
- switch (name)
- {
- default:
- break;
- case NSV::PROP_uX:
- {
- SWFMatrix m = getMatrix();
- double x = infinite_to_zero( val.to_number() );
- m.tx = pixelsToTwips(x);
- setMatrix(m); // no need to update caches when only changing
translation
-
- // m_accept_anim_moves = false;
- return true;
- }
- case NSV::PROP_uY:
- {
- SWFMatrix m = getMatrix();
- double y = infinite_to_zero( val.to_number() );
- m.ty = pixelsToTwips(y);
- setMatrix(m); // no need to update caches when only changing
translation
-
- // m_accept_anim_moves = false;
- return true;
- }
- case NSV::PROP_uWIDTH:
- {
- double nw = val.to_number();
- if (!isFinite(nw) )
- {
- // might be our fault, see the TODO above
- // (missing to pass as_environment out..)
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Attempt to set TextField._width to %g"), nw);
- );
- return true;
- }
-
- if ( nw < 0 )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Attempt to set TextField._width to a "
- "negative number: %g, toggling sign"), nw);
- );
- nw = -nw;
- }
-
- if ( _bounds.width() == pixelsToTwips(nw) )
- {
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("TextField width already == %g, nothing to do to "
- "change it", nw);
-#endif
- return true; // nothing to do
- }
- if ( _bounds.is_null() )
- {
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("NULL TextField bounds : %s", _bounds);
-#endif
- return true;
- }
-
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("Chaging TextField width to %g", nw);
-#endif
-
- set_invalidated();
-
- // Modify TextField drawing rectangle
- // TODO: check which anchor point we should use !
- boost::int32_t xmin = _bounds.get_x_min();
- boost::int32_t ymin = _bounds.get_y_min();
- boost::int32_t ymax = _bounds.get_y_max();
- boost::int32_t xmax = xmin + pixelsToTwips(nw);
-
- assert(xmin <= xmax);
- _bounds.set_to_rect(xmin, ymin, xmax, ymax);
- assert( _bounds.width() == pixelsToTwips(nw) );
-
- // previously truncated text might get visible now
- // TODO: if nested masks were implemented we would
- // not need to reformat text here
- format_text();
-
- return true;
- }
- case NSV::PROP_uHEIGHT:
- {
- double nh = val.to_number();
- if (!isFinite(nh) )
- {
- // might be our fault, see the TODO above (missing to pass
- // as_environment out..)
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Attempt to set TextField._height to %g"), nh);
- );
- return true;
- }
-
- if ( nh < 0.0f )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("Attempt to set TextField._height to a negative "
- "number: %g, toggling sign"), nh);
- );
- nh = -nh;
- }
-
- if ( _bounds.height() == pixelsToTwips(nh) )
- {
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("TextField height already == %g, nothing to do to "
- "change it", nh);
-#endif // GNASH_DEBUG_TEXTFIELDS
- return true; // nothing to do
- }
- if ( _bounds.is_null() )
- {
- return true;
- }
-
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("Changing TextField height to %g", nh);
-#endif // GNASH_DEBUG_TEXTFIELDS
- set_invalidated();
-
- // Modify TextField drawing rectangle
- // TODO: check which anchor point we should use !
- boost::int32_t xmin = _bounds.get_x_min();
- boost::int32_t xmax = _bounds.get_x_max();
- boost::int32_t ymin = _bounds.get_y_min();
- _bounds.set_to_rect(xmin, ymin, xmax, ymin + pixelsToTwips(nh) );
-
- assert(_bounds.height() == pixelsToTwips(nh));
-
- // previously truncated text might get visible now
- // TODO: if nested masks were implemented we would
- // not need to reformat text here
- format_text();
-
- return true;
- }
- case NSV::PROP_uVISIBLE:
- {
- set_visible(val.to_bool());
- return true;
- }
- case NSV::PROP_uALPHA:
- {
- // @@ TODO this should be generic to class DisplayObject!
- // Arg is in percent.
- cxform cx = get_cxform();
- cx.aa = (boost::int16_t)(val.to_number() * 2.56);
- set_cxform(cx);
- return true;
- }
- // @@ TODO see TextField members in Flash MX docs
- } // end switch
-
-
- return as_object::set_member(name, val, nsname, ifFound);
-}
-
-bool
-TextField::get_member(string_table::key name, as_value* val,
- string_table::key nsname)
-{
- //log_debug("TextField.get_member(%s)", name);
-
- // FIXME: Turn all standard members into getter/setter properties
- // of the TextField class. See attachTextFieldInterface()
-
- switch (name)
- {
- default:
- break;
- case NSV::PROP_uVISIBLE:
- {
- val->set_bool(visible());
- return true;
- }
- case NSV::PROP_uALPHA:
- {
- // @@ TODO this should be generic to class DisplayObject!
- const cxform& cx = get_cxform();
- val->set_double(cx.aa / 2.56);
- return true;
- }
- case NSV::PROP_uX:
- {
- SWFMatrix m = getMatrix();
- val->set_double(twipsToPixels(m.tx));
- return true;
- }
- case NSV::PROP_uY:
- {
- SWFMatrix m = getMatrix();
- val->set_double(twipsToPixels(m.ty));
- return true;
- }
- case NSV::PROP_uWIDTH:
- {
- val->set_double(twipsToPixels(get_width()));
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("Got TextField width == %s", *val);
-#endif // GNASH_DEBUG_TEXTFIELDS
- return true;
- }
- case NSV::PROP_uHEIGHT:
- {
- val->set_double(twipsToPixels(get_height()));
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug("Got TextField height == %s", *val);
-#endif // GNASH_DEBUG_TEXTFIELDS
- return true;
- }
- } // end switch
-
- return as_object::get_member(name, val, nsname);
-
-}
-
-
-float
-TextField::align_line(TextAlignment align,
- int last_line_start_record, float x)
-{
-
- float width = _bounds.width();
- float right_margin = getRightMargin();
-
- float extra_space = (width - right_margin) - x - PADDING_TWIPS;
-
- //assert(extra_space >= 0.0f);
- if (extra_space <= 0.0f)
- {
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug(_("TextField text doesn't fit in its boundaries: "
- "width %g, margin %g - nothing to align"),
- width, right_margin);
-#endif
- return 0.0f;
- }
-
- float shift_right = 0.0f;
-
- if (align == ALIGN_LEFT)
- {
- // Nothing to do; already aligned left.
- return 0.0f;
- }
- else if (align == ALIGN_CENTER)
- {
- // Distribute the space evenly on both sides.
- shift_right = extra_space / 2;
- }
- else if (align == ALIGN_RIGHT)
- {
- // Shift all the way to the right.
- shift_right = extra_space;
- }
-
- // Shift the beginnings of the records on this line.
- for (unsigned int i = last_line_start_record; i < _textRecords.size(); ++i)
- {
- SWF::TextRecord& rec = _textRecords[i];
-
- //if ( rec.hasXOffset() ) // why?
- rec.setXOffset(rec.xOffset() + shift_right);
- }
- return shift_right;
-}
-
-boost::intrusive_ptr<const Font>
-TextField::setFont(boost::intrusive_ptr<const Font> newfont)
-{
- if ( newfont == _font ) return _font;
-
- boost::intrusive_ptr<const Font> oldfont = _font;
- set_invalidated();
- _font = newfont;
- format_text();
- return oldfont;
-}
-
-
-void
-TextField::insertTab(SWF::TextRecord& rec, boost::int32_t& x, float scale)
-{
- // tab (ASCII HT)
- const int space = 32;
- int index = rec.getFont()->get_glyph_index(space, _embedFonts);
- if ( index == -1 )
- {
- IF_VERBOSE_MALFORMED_SWF (
- log_error(_("TextField: missing glyph for space char (needed "
- "for TAB). Make sure DisplayObject shapes for font "
- "%s are being exported into your SWF file."),
- rec.getFont()->name());
- );
- }
- else
- {
- SWF::TextRecord::GlyphEntry ge;
- ge.index = index;
- ge.advance = scale * rec.getFont()->get_advance(index,
- _embedFonts);
-
- const int tabstop = 8;
- rec.addGlyph(ge, tabstop);
- x += ge.advance * tabstop;
- }
-}
-
-void
-TextField::format_text()
-{
- _textRecords.clear();
-
- // nothing more to do if text is empty
- if ( _text.empty() )
- {
- // TODO: should we still reset _bounds if autoSize != autoSizeNone ?
- // not sure we should...
- reset_bounding_box(0, 0);
- return;
- }
-
- // See bug #24266
- const rect& defBounds = _bounds;
-
- AutoSizeValue autoSize = getAutoSize();
- if ( autoSize != autoSizeNone )
- {
- // define GNASH_DEBUG_TEXT_FORMATTING on top to get useful info
- //LOG_ONCE( log_debug(_("TextField.autoSize != 'none' TESTING")) );
-
- // When doing WordWrap we don't want to change
- // the boundaries. See bug #24348
- if (! doWordWrap() )
- {
- _bounds.set_to_rect(0, 0, 0, 0); // this is correct for 'true'
- }
- }
-
- // Should get info from autoSize too maybe ?
- TextAlignment textAlignment = getTextAlignment();
-
- // FIXME: I don't think we should query the definition
- // to find the appropriate font to use, as ActionScript
- // code should be able to change the font of a TextField
- //
- if (!_font)
- {
- log_error(_("No font for TextField!"));
- return;
- }
-
- boost::uint16_t fontHeight = getFontHeight();
- float scale = fontHeight / (float)_font->unitsPerEM(_embedFonts);
- float fontDescent = _font->descent() * scale;
- float fontLeading = _font->leading() * scale;
- boost::uint16_t leftMargin = getLeftMargin();
- boost::uint16_t rightMargin = getRightMargin();
- boost::uint16_t indent = getIndent();
- boost::uint16_t blockIndent = getBlockIndent();
- bool underlined = getUnderlined();
-
- //log_debug("%s: fontDescent:%g, fontLeading:%g, fontHeight:%g, scale:%g",
- // getTarget(), fontDescent, fontLeading, fontHeight, scale);
-
- SWF::TextRecord rec; // one to work on
- rec.setFont(_font.get());
- rec.setUnderline(underlined);
- rec.setColor(getTextColor());
- rec.setXOffset(PADDING_TWIPS +
- std::max(0, leftMargin + indent + blockIndent));
- rec.setYOffset(PADDING_TWIPS + fontHeight + (fontLeading - fontDescent));
- rec.setTextHeight(fontHeight);
-
- boost::int32_t x = static_cast<boost::int32_t>(rec.xOffset());
- boost::int32_t y = static_cast<boost::int32_t>(rec.yOffset());
-
- // Start the bbox at the upper-left corner of the first glyph.
- reset_bounding_box(x, y - fontDescent + fontHeight);
-
- float leading = getLeading();
- leading += fontLeading * scale; // not sure this is correct...
-
- int last_code = -1; // only used if _embedFonts
- int last_space_glyph = -1;
- int last_line_start_record = 0;
-
- unsigned int idx = 0;
- m_xcursor = x;
- m_ycursor = y;
-
- assert(! _text.empty() );
-
- boost::uint32_t code = 0;
-
- // String iterators are very sensitive to
- // potential changes to the string (to allow for copy-on-write).
- // So there must be no external changes to the string or
- // calls to most non-const member functions during this loop.
- // Especially not c_str() or data().
- std::wstring::const_iterator it = _text.begin();
- const std::wstring::const_iterator e = _text.end();
-
- while (it != e)
- {
- code = *it++;
- if (!code) break;
-
- if ( _embedFonts )
- {
- x += rec.getFont()->get_kerning_adjustment(last_code,
- static_cast<int>(code)) * scale;
- last_code = static_cast<int>(code);
- }
-
- // Expand the bounding-box to the lower-right corner of each glyph as
- // we generate it.
- m_text_bounding_box.expand_to_point(x, y + fontDescent);
-
- switch (code)
- {
- case 27:
- // Ignore escape
- break;
- case 9:
- insertTab(rec, x, scale);
- break;
- case 13:
- case 10:
- {
- // newline.
-
- // Frigging Flash seems to use '\r' (13) as its
- // default newline DisplayObject. If we get DOS-style \r\n
- // sequences, it'll show up as double newlines, so maybe we
- // need to detect \r\n and treat it as one newline.
-
- // Close out this stretch of glyphs.
- _textRecords.push_back(rec);
- align_line(textAlignment, last_line_start_record, x);
-
- // Expand bounding box to include last column of text ...
- if ( _autoSize != autoSizeNone ) {
- _bounds.expand_to_point(x + PADDING_TWIPS,
- y + PADDING_TWIPS);
- }
-
- // new paragraphs get the indent.
- x = std::max(0, leftMargin + indent) + PADDING_TWIPS;
- y += fontHeight + leading;
-
- // Start a new record on the next line. Other properties of the
- // TextRecord should be left unchanged.
- rec.clearGlyphs();
- rec.setXOffset(x);
- rec.setYOffset(y);
-
- last_space_glyph = -1;
- last_line_start_record = _textRecords.size();
-
- continue;
- }
- case 8:
- // Backspace
-
- // This is a limited hack to enable overstrike effects.
- // It backs the cursor up by one DisplayObject and then
continues
- // the layout. E.g. you can use this to display an underline
- // cursor inside a simulated text-entry box.
- //
- // ActionScript understands the '\b' escape sequence
- // for inserting a BS DisplayObject.
- //
- // ONLY WORKS FOR BACKSPACING OVER ONE CHARACTER, WON'T BS
- // OVER NEWLINES, ETC.
-
- if (!rec.glyphs().empty())
- {
- // Peek at the previous glyph, and zero out its advance
- // value, so the next char overwrites it.
- float advance = rec.glyphs().back().advance;
- x -= advance;
- // Remove one glyph
- rec.clearGlyphs(1);
- }
- continue;
- case '<':
- if (_html)
- {
- LOG_ONCE(log_debug(_("HTML in a text field is unsupported,
"
- "gnash will just ignore the tags and "
- "print their content")));
-
- std::wstring discard;
- bool complete = parseHTML(discard, it, e);
-
- if (!complete) continue;
- else break;
-
- }
- // If HTML isn't enabled, carry on and insert the glyph.
-
- case 32:
- last_space_glyph = rec.glyphs().size();
- // Don't break, as we still need to insert the space glyph.
-
- default:
- {
-
- // The font table holds up to 65535 glyphs. Casting
- // from uint32_t would, in the event that the code
- // is higher than 65535, result in the wrong DisplayObject
- // being chosen. Flash can currently only handle 16-bit
- // values.
- int index = rec.getFont()->get_glyph_index(
- static_cast<boost::uint16_t>(code), _embedFonts);
-
- IF_VERBOSE_MALFORMED_SWF (
- if (index == -1)
- {
- // Missing glyph! Log the first few errors.
- static int s_log_count = 0;
- if (s_log_count < 10)
- {
- s_log_count++;
- if (_embedFonts)
- {
- log_swferror(_("TextField: missing embedded "
- "glyph for char %d. Make sure
DisplayObject "
- "shapes for font %s are being exported "
- "into your SWF file"),
- code, _font->name());
- }
- else
- {
- log_swferror(_("TextField: missing device "
- "glyph for char %d. Maybe you don't have "
- "font '%s' installed in your system."),
- code, _font->name());
- }
- }
-
- // Drop through and use index == -1; this will display
- // using the empty-box glyph
- }
- );
-
- SWF::TextRecord::GlyphEntry ge;
- ge.index = index;
- ge.advance = scale * rec.getFont()->get_advance(index,
- _embedFonts);
-
- rec.addGlyph(ge);
-
- x += ge.advance;
- }
- }
-
- float width = defBounds.width();
- if (x >= width - rightMargin - PADDING_TWIPS)
- {
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug("Text in TextField %s exceeds width [ _bounds %s ]",
- getTarget(), _bounds);
-#endif
-
- // No wrap and no resize: truncate
- if (!doWordWrap() && autoSize == autoSizeNone)
- {
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug(" wordWrap=false, autoSize=none");
-#endif
- // Truncate long line, but keep expanding text box
- bool newlinefound = false;
- while (it != e)
- {
- code = *it++;
- if (_embedFonts)
- {
- x += rec.getFont()->get_kerning_adjustment(last_code,
- static_cast<int>(code)) * scale;
- last_code = code;
- }
- // Expand the bounding-box to the lower-right corner
- // of each glyph, even if we don't display it
- m_text_bounding_box.expand_to_point(x, y + fontDescent);
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug("Text bbox expanded to %s (width: %f)",
- m_text_bounding_box, m_text_bounding_box.width());
-#endif
-
- if (code == 13 || code == 10)
- {
- newlinefound = true;
- break;
- }
-
- int index = rec.getFont()->get_glyph_index(
- static_cast<boost::uint16_t>(code), _embedFonts);
- x += scale * rec.getFont()->get_advance(index,
_embedFonts);
-
- }
- if (!newlinefound) break;
- }
- else if ( doWordWrap() )
- {
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug(" wordWrap=true");
-#endif
-
- // Insert newline if there's space or autosize != none
-
- // Close out this stretch of glyphs.
- _textRecords.push_back(rec);
-
- float previous_x = x;
- x = leftMargin + blockIndent + PADDING_TWIPS;
- y += fontHeight + leading;
-
- // Start a new record on the next line.
- rec.clearGlyphs();
- rec.setXOffset(x);
- rec.setYOffset(y);
-
- // TODO : what if m_text_glyph_records is empty ?
- // Is it possible ?
- assert(!_textRecords.empty());
- SWF::TextRecord& last_line = _textRecords.back();
- if (last_space_glyph == -1)
- {
- // Pull the previous glyph down onto the
- // new line.
- if (!last_line.glyphs().empty())
- {
- rec.addGlyph(last_line.glyphs().back());
- x += last_line.glyphs().back().advance;
- previous_x -= last_line.glyphs().back().advance;
- last_line.clearGlyphs(1);
- }
- }
- else
- {
- // Move the previous word down onto the next line.
-
- previous_x -= last_line.glyphs()[last_space_glyph].advance;
-
- const SWF::TextRecord::Glyphs::size_type lineSize =
- last_line.glyphs().size();
- for (unsigned int i = last_space_glyph + 1; i < lineSize;
- ++i)
- {
- rec.addGlyph(last_line.glyphs()[i]);
- x += last_line.glyphs()[i].advance;
- previous_x -= last_line.glyphs()[i].advance;
- }
- last_line.clearGlyphs(lineSize - last_space_glyph);
- }
-
- align_line(textAlignment, last_line_start_record, previous_x);
-
- last_space_glyph = -1;
- last_line_start_record = _textRecords.size();
-
- }
- else
- {
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug(" wordWrap=%d, autoSize=%d", _wordWrap, _autoSize);
-#endif
- }
- }
-
- if (y > (defBounds.height() - PADDING_TWIPS) &&
- autoSize == autoSizeNone )
- {
-#ifdef GNASH_DEBUG_TEXT_FORMATTING
- log_debug("Text with wordWrap exceeds height of box");
-#endif
- rec.clearGlyphs();
- // TODO: should still compute m_text_bounds !
- LOG_ONCE(log_unimpl("Computing text bounds of a TextField "
- "containing text that doesn't fit the box
vertically"));
- break;
- }
-
- if (m_cursor > idx)
- {
- m_xcursor = x;
- m_ycursor = y;
- }
- idx++;
-
- // TODO: HTML markup
- }
-
- // Expand bounding box to include the whole text (if autoSize)
- if ( _autoSize != autoSizeNone )
- {
- _bounds.expand_to_point(x+PADDING_TWIPS, y+PADDING_TWIPS);
- }
-
- // Add this line to our output.
- if (!rec.glyphs().empty()) _textRecords.push_back(rec);
-
- float extra_space = align_line(textAlignment, last_line_start_record, x);
-
- m_xcursor += static_cast<int>(extra_space);
- m_ycursor -= fontHeight + (fontLeading - fontDescent);
-}
-
-TextField::VariableRef
-TextField::parseTextVariableRef(const std::string& variableName) const
-{
- VariableRef ret;
- ret.first = 0;
-
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("VariableName: %s"), variableName);
-#endif
-
- /// Why isn't get_environment const again ?
- as_environment& env = const_cast<TextField*>(this)->get_environment();
-
- as_object* target = env.get_target();
- if ( ! target )
- {
- IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("Current environment has no target, "
- "can't bind VariableName (%s) associated to "
- "text field. Gnash will try to register "
- "again on next access."), variableName);
- );
- return ret;
- }
-
- // If the variable string contains a path, we extract
- // the appropriate target from it and update the variable
- // name. We copy the string so we can assign to it if necessary.
- std::string parsedName = variableName;
- std::string path, var;
- if (as_environment::parse_path(variableName, path, var))
- {
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("Variable text Path: %s, Var: %s"), path, var);
-#endif
- // find target for the path component
- // we use our parent's environment for this
- target = env.find_object(path);
-
- parsedName = var;
- }
-
- if ( ! target )
- {
- IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("VariableName associated to text field refers "
- "to an unknown target (%s). It is possible that the "
- "DisplayObject will be instantiated later in the SWF "
- "stream. Gnash will try to register again on next "
- "access."), path);
- );
- return ret;
- }
-
- ret.first = target;
- ret.second = _vm.getStringTable().find(parsedName);
-
- return ret;
-}
-
-void
-TextField::registerTextVariable()
-{
-//#define DEBUG_DYNTEXT_VARIABLES 1
-
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("registerTextVariable() called"));
-#endif
-
- if ( _text_variable_registered )
- {
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("registerTextVariable() no-op call (already registered)"));
-#endif
- return;
- }
-
- if ( _variable_name.empty() )
- {
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("string is empty, consider as registered"));
-#endif
- _text_variable_registered=true;
- return;
- }
-
- VariableRef varRef = parseTextVariableRef(_variable_name);
- as_object* target = varRef.first;
- if ( ! target )
- {
- log_debug(_("VariableName associated to text field (%s) refer to "
- "an unknown target. It is possible that the DisplayObject "
- "will be instantiated later in the SWF stream. "
- "Gnash will try to register again on next access."),
- _variable_name);
- return;
- }
-
- string_table::key key = varRef.second;
-
- // check if the VariableName already has a value,
- // in that case update text value
- as_value val;
-
- int version = _vm.getSWFVersion();
-
- if (target->get_member(key, &val) )
- {
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("target object (%s @ %p) does have a member named %s"),
- typeName(*target), (void*)target, _vm.getStringTable().value(key));
-#endif
- // TODO: pass environment to to_string ?
- // as_environment& env = get_environment();
- setTextValue(utf8::decodeCanonicalString(val.to_string(), version));
- }
- else if ( _textDefined )
- {
- as_value newVal = as_value(utf8::encodeCanonicalString(_text,
version));
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("target sprite (%s @ %p) does NOT have a member "
- "named %s (no problem, we'll add it with value %s)"),
- typeName(*target), (void*)target,
- _vm.getStringTable().value(key), newVal);
-#endif
- target->set_member(key, newVal);
- }
- else
- {
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug(_("target sprite (%s @ %p) does NOT have a member "
- "named %s, and we don't have text defined"),
- typeName(*target), (void*)target,
- _vm.getStringTable().value(key));
-#endif
- }
-
- MovieClip* sprite = target->to_movie();
-
- if ( sprite )
- {
- // add the textfield variable to the target sprite
- // TODO: have set_textfield_variable take a string_table::key instead ?
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug("Calling set_textfield_variable(%s) against sprite %s",
- _vm.getStringTable().value(key), sprite->getTarget());
-#endif
- sprite->set_textfield_variable(_vm.getStringTable().value(key), this);
-
- }
- _text_variable_registered=true;
-
-}
-
-/// Parses an HTML tag (between < and >) and puts
-/// the contents into tag. Returns false if the
-/// tag was incomplete. The iterator is moved to after
-/// the closing tag or the end of the string.
-bool
-TextField::parseHTML(std::wstring& tag, std::wstring::const_iterator& it,
- const std::wstring::const_iterator& e) const
-{
-
- bool complete = false;
-
- while (it != e)
- {
- if (*it == '>')
- {
- ++it;
- complete = true;
- break;
- }
-
- // Check for NULL DisplayObject
- if (*it == 0) break;
-
- tag.push_back(*it++);
- }
-
-#ifdef GNASH_DEBUG_TEXTFIELDS
- log_debug ("HTML tag: %s", utf8::encodeCanonicalString(tag, 7));
-#endif
-
- return complete;
-}
-
-void
-TextField::set_variable_name(const std::string& newname)
-{
- if ( newname != _variable_name )
- {
- _variable_name = newname;
-
- // The name was empty or undefined, so there's nothing more to do.
- if (_variable_name.empty()) return;
-
- _text_variable_registered = false;
-
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug("Calling updateText after change of variable name");
-#endif
-
- // Use the original definition text if this isn't dynamically
- // created.
- if (_tag) updateText(_tag->defaultText());
-
-#ifdef DEBUG_DYNTEXT_VARIABLES
- log_debug("Calling registerTextVariable after change of variable "
- "name and updateText call");
-#endif
- registerTextVariable();
- }
-}
-
-/// 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& global)
-{
- static boost::intrusive_ptr<builtin_function> cl = NULL;
-
- if (!cl)
- {
- VM& vm = global.getVM();
-
- if (vm.getSWFVersion() < 6) {
- /// Version 5 or less: no initial prototype
- cl = new builtin_function(&textfield_ctor, 0);
- }
- else {
- /// Version 6 upward: limited initial prototype
- as_object* iface = getTextFieldInterface(vm);
- cl = new builtin_function(&textfield_ctor, iface);
- }
-
- vm.addStatic(cl.get());
-
- // replicate static members to class, to be able to access
- // all methods as static functions
- attachTextFieldStaticMembers(*cl);
-
- }
-
- // Register _global.TextField
- global.init_member("TextField", cl.get());
-}
-
-bool
-TextField::pointInShape(boost::int32_t x, boost::int32_t y) const
-{
- SWFMatrix wm = getWorldMatrix();
- point lp(x, y);
- wm.invert().transform(lp);
- return _bounds.point_test(lp.x, lp.y);
-}
-
-bool
-TextField::getDrawBorder() const
-{
- return _drawBorder;
-}
-
-void
-TextField::setDrawBorder(bool val)
-{
- if ( _drawBorder != val )
- {
- set_invalidated();
- _drawBorder = val;
- }
-}
-
-rgba
-TextField::getBorderColor() const
-{
- return _borderColor;
-}
-
-void
-TextField::setBorderColor(const rgba& col)
-{
- if ( _borderColor != col )
- {
- set_invalidated();
- _borderColor = col;
- }
-}
-
-bool
-TextField::getDrawBackground() const
-{
- return _drawBackground;
-}
-
-void
-TextField::setDrawBackground(bool val)
-{
- if ( _drawBackground != val )
- {
- set_invalidated();
- _drawBackground = val;
- }
-}
-
-rgba
-TextField::getBackgroundColor() const
-{
- return _backgroundColor;
-}
-
-void
-TextField::setBackgroundColor(const rgba& col)
-{
- if ( _backgroundColor != col )
- {
- set_invalidated();
- _backgroundColor = col;
- }
-}
-
-void
-TextField::setTextColor(const rgba& col)
-{
- if (_textColor != col) {
-
- set_invalidated();
- _textColor = col;
- std::for_each(_textRecords.begin(), _textRecords.end(),
- boost::bind(&SWF::TextRecord::setColor, _1, _textColor));
- }
-}
-
-void
-TextField::setEmbedFonts(bool use)
-{
- if ( _embedFonts != use )
- {
- set_invalidated();
- _embedFonts=use;
- format_text();
- }
-}
-
-void
-TextField::setWordWrap(bool on)
-{
- if ( _wordWrap != on )
- {
- set_invalidated();
- _wordWrap=on;
- format_text();
- }
-}
-
-cxform
-TextField::get_world_cxform() const
-{
- // This is not automatically tested. See testsuite/samples/input-fields.swf
- // for a manual check.
-
- // If using a device font (PP compatibility), do not take parent cxform
- // into account.
- if (!getEmbedFonts()) return cxform();
-
- return DisplayObject::get_world_cxform();
-}
-
-void
-TextField::setLeading(boost::uint16_t h)
-{
- if ( _leading != h )
- {
- set_invalidated();
- _leading = h;
- format_text();
- }
-}
-
-void
-TextField::setUnderlined(bool v)
-{
- if ( _underlined != v )
- {
- set_invalidated();
- _underlined = v;
- format_text();
- }
-}
-
-void
-TextField::setAlignment(TextAlignment h)
-{
- if ( _alignment != h )
- {
- set_invalidated();
- _alignment = h;
- format_text();
- }
-}
-
-void
-TextField::setIndent(boost::uint16_t h)
-{
- if ( _indent != h )
- {
- set_invalidated();
- _indent = h;
- format_text();
- }
-}
-
-void
-TextField::setBlockIndent(boost::uint16_t h)
-{
- if ( _blockIndent != h )
- {
- set_invalidated();
- _blockIndent = h;
- format_text();
- }
-}
-
-void
-TextField::setRightMargin(boost::uint16_t h)
-{
- if ( _rightMargin != h )
- {
- set_invalidated();
- _rightMargin = h;
- format_text();
- }
-}
-
-void
-TextField::setLeftMargin(boost::uint16_t h)
-{
- if (_leftMargin != h)
- {
- set_invalidated();
- _leftMargin = h;
- format_text();
- }
-}
-
-void
-TextField::setFontHeight(boost::uint16_t h)
-{
- if ( _fontHeight != h )
- {
- set_invalidated();
- _fontHeight = h;
- format_text();
- }
-}
-
-
-TextField::AutoSizeValue
-TextField::parseAutoSizeValue(const std::string& val)
-{
- StringNoCaseEqual cmp;
-
- if ( cmp(val, "left") )
- {
- return autoSizeLeft;
- }
- if ( cmp(val, "right") )
- {
- return autoSizeRight;
- }
- if ( cmp(val, "center") )
- {
- return autoSizeCenter;
- }
- return autoSizeNone;
-
-}
-
-
-const char*
-TextField::autoSizeValueName(AutoSizeValue val)
-{
- switch (val)
- {
- case autoSizeLeft:
- return "left";
- case autoSizeRight:
- return "right";
- case autoSizeCenter:
- return "center";
- case autoSizeNone:
- default:
- return "none";
- }
-
-}
-
-
-TextField::TypeValue
-TextField::parseTypeValue(const std::string& val)
-{
- StringNoCaseEqual cmp;
-
- if (cmp(val, "input")) return typeInput;
- if (cmp(val, "dynamic")) return typeDynamic;
- return typeInvalid;
-
-}
-
-
-const char*
-TextField::typeValueName(TypeValue val)
-{
- switch (val)
- {
- case typeInput:
- //log_debug("typeInput returned as 'input'");
- return "input";
- case typeDynamic:
- //log_debug("typeDynamic returned as 'dynamic'");
- return "dynamic";
- default:
- //log_debug("invalid type %d returned as 'invalid'", (int)val);
- return "invalid";
- }
-
-}
-
-void
-TextField::setAutoSize(AutoSizeValue val)
-{
- if ( val == _autoSize ) return;
-
- set_invalidated();
-
- _autoSize = val;
- format_text();
-}
-
-TextField::TextAlignment
-TextField::getTextAlignment()
-{
- TextAlignment textAlignment = getAlignment();
- if ( _autoSize == autoSizeCenter ) textAlignment = ALIGN_CENTER;
- else if ( _autoSize == autoSizeLeft ) textAlignment = ALIGN_LEFT;
- else if ( _autoSize == autoSizeRight ) textAlignment = ALIGN_RIGHT;
- return textAlignment;
-}
-
-void
-TextField::onChanged()
-{
- as_value met(PROPNAME("onChanged"));
- as_value targetVal(this);
- callMethod(NSV::PROP_BROADCAST_MESSAGE, met, targetVal);
-}
-
-/// This is called by movie_root when focus is applied to this TextField.
-//
-/// The return value is true if the TextField can recieve focus.
-bool
-TextField::handleFocus()
-{
-
- set_invalidated();
-
- /// Select the entire text on focus.
- setSelection(0, _text.length());
-
- m_has_focus = true;
-
- // why should we add to the key listener list every time
- // we call setFocus()???
- _vm.getRoot().add_key_listener(this);
-
- m_cursor = _text.size();
- format_text();
- return true;
-}
-
-/// This is called by movie_root when focus is removed from the
-/// current TextField.
-void
-TextField::killFocus()
-{
- if ( ! m_has_focus ) return; // nothing to do
-
- set_invalidated();
- m_has_focus = false;
-
- movie_root& root = _vm.getRoot();
- root.remove_key_listener(this);
- format_text(); // is this needed ?
-
-}
-
-void
-TextField::markReachableResources() const
-{
-
- if (_tag) _tag->setReachable();
-
- if (_font) _font->setReachable();
-
- // recurse to parent...
- markDisplayObjectReachable();
-}
-
-/// TextField interface functions
-
-namespace {
-
-void
-attachPrototypeProperties(as_object& o)
-{
- // Standard flags.
- const int flags = as_prop_flags::dontDelete
- |as_prop_flags::dontEnum;
-
- // SWF6 or higher
- const int swf6Flags = flags | as_prop_flags::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);
-
- getset = new builtin_function(textfield_variable);
- o.init_property("variable", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_background);
- o.init_property("background", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_text);
- o.init_property("text", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_backgroundColor);
- o.init_property("backgroundColor", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_border);
- o.init_property("border", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_borderColor);
- o.init_property("borderColor", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_textColor);
- o.init_property("textColor", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_embedFonts);
- o.init_property("embedFonts", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_autoSize);
- o.init_property("autoSize", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_type);
- o.init_property("type", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_wordWrap);
- o.init_property("wordWrap", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_html);
- o.init_property("html", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_selectable);
- o.init_property("selectable", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_length);
- o.init_property("length", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_maxscroll);
- o.init_property("maxscroll", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_maxhscroll);
- o.init_property("maxhscroll", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_maxChars);
- o.init_property("maxChars", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_bottomScroll);
- o.init_property("bottomScroll", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_scroll);
- o.init_property("scroll", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_hscroll);
- o.init_property("hscroll", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_restrict);
- o.init_property("restrict", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_multiline);
- o.init_property("multiline", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_password);
- o.init_property("password", *getset, *getset, swf6Flags);
- getset = new builtin_function(textfield_htmlText);
- o.init_property("htmlText", *getset, *getset, swf6Flags);
-}
-
-
-as_value
-textfield_background(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- if (fn.nargs == 0) {
- return as_value(ptr->getBackgroundColor().toRGB());
- }
- else {
- rgba newColor;
- newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_int()));
- ptr->setBackgroundColor(newColor);
- }
-
- return as_value();
-}
-
-as_value
-textfield_borderColor(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- if ( fn.nargs == 0 ) // getter
- {
- return ptr->autoSizeValueName(ptr->getAutoSize());
- }
- else // setter
- {
- const as_value& arg = fn.arg(0);
- if ( arg.is_bool() )
- {
- if ( arg.to_bool() ) // true == left
- {
- ptr->setAutoSize( TextField::autoSizeLeft );
- }
- else
- {
- ptr->setAutoSize( TextField::autoSizeNone );
- }
- }
- else
- {
- std::string strval = arg.to_string();
- TextField::AutoSizeValue val = ptr->parseAutoSizeValue(strval);
- ptr->setAutoSize( val );
- }
- }
-
- return as_value();
-}
-
-as_value
-textfield_type(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- 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)
-{
- // TODO: make this a DisplayObject::getDepth_method function...
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- int n = text->get_depth();
-
- return as_value(n);
-
-}
-
-as_value
-textfield_getFontList(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE(log_unimpl("TextField.getFontList()"));
-
- return as_value();
-}
-
-as_value
-textfield_getNewTextFormat(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE(log_unimpl("TextField.getNewTextFormat()"));
-
- return as_value();
-}
-
-as_value
-textfield_getTextFormat(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- boost::intrusive_ptr<TextFormat_as> tf = new TextFormat_as;
- 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->italicedSet(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(tf.get());
-}
-
-as_value
-textfield_setTextFormat(const fn_call& fn)
-{
-
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- 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());
- }
-
- as_object* obj = fn.arg(0).to_object().get();
- if ( ! obj )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("TextField.setTextFormat(%s) : %s", ss.str(),
- _("first argument is not an object"))
- );
- return as_value();
- }
-
- TextFormat_as* tf = dynamic_cast<TextFormat_as*>(obj);
- if ( ! 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 ( tf->alignDefined() ) text->setAlignment(tf->align());
- if ( tf->sizeDefined() ) text->setFontHeight(tf->size()); // keep twips
- if ( tf->indentDefined() ) text->setIndent(tf->indent());
- if ( tf->blockIndentDefined() ) text->setBlockIndent(tf->blockIndent());
- if ( tf->leadingDefined() ) text->setLeading(tf->leading());
- if ( tf->leftMarginDefined() ) text->setLeftMargin(tf->leftMargin());
- if ( tf->rightMarginDefined() ) text->setRightMargin(tf->rightMargin());
- if ( tf->colorDefined() ) text->setTextColor(tf->color());
- if ( tf->underlinedDefined() ) text->setUnderlined(tf->underlined());
-
- if ( tf->fontDefined() )
- {
- const std::string& fontName = tf->font();
- if ( ! fontName.empty() )
- {
- bool bold = tf->bold();
- bool italic = tf->italiced();
-
- // 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
-
- LOG_ONCE( log_unimpl("TextField.setTextFormat() discards url, target, "
- "tabStops, bullet and display") );
-
- return as_value();
-
-}
-
-as_value
-textfield_setNewTextFormat(const fn_call& fn)
-{
- //boost::intrusive_ptr<TextField> text =
ensureType<TextField>(fn.this_ptr);
- //UNUSED(text);
-
- LOG_ONCE( log_unimpl("TextField.setNewTextFormat(), we'll delegate "
- "to setTextFormat") );
- return textfield_setTextFormat(fn);
-
- //return as_value();
-}
-
-as_value
-textfield_password(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- LOG_ONCE(log_unimpl("TextField.password"));
-
- 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)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- LOG_ONCE(log_unimpl("TextField.multiline"));
-
- 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)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.restrict"));
-
- return as_value();
-}
-
-as_value
-textfield_bottomScroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.bottomScroll"));
-
- return as_value();
-}
-
-as_value
-textfield_maxhscroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.maxhscroll"));
-
- 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)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- LOG_ONCE(log_unimpl("TextField.maxChars"));
-
- 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(fn.arg(0).to_int());
- return as_value();
-}
-
-as_value
-textfield_text(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
- if (!fn.nargs)
- {
- // Getter
- //
- // FIXME: should return text without HTML tags.
- return as_value(ptr->get_text_value());
- }
-
- // Setter
- int version = ptr->getVM().getSWFVersion();
- ptr->setTextValue(
- utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
-
- return as_value();
-}
-
-as_value
-textfield_htmlText(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> ptr = ensureType<TextField>(fn.this_ptr);
- if (!fn.nargs)
- {
- // Getter
- return as_value(ptr->get_text_value());
- }
-
- // Setter
- int version = ptr->getVM().getSWFVersion();
- ptr->setTextValue(
- 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)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- 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 = text->getVM().getSWFVersion();
- if (version < 8 && replace.empty()) return as_value();
-
- text->replaceSelection(replace);
-
- return as_value();
-}
-
-as_value
-textfield_scroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.scroll()"));
-
- return as_value();
-}
-
-as_value
-textfield_hscroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.hscroll()"));
-
- return as_value();
-}
-
-as_value
-textfield_maxscroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE (log_unimpl("TextField.maxscroll"));
-
- return as_value();
-}
-
-as_value
-textfield_replaceText(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
- UNUSED(text);
-
- LOG_ONCE(log_unimpl("TextField.replaceText()"));
-
- return as_value();
-}
-
-as_value
-textfield_removeTextField(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField> text = ensureType<TextField>(fn.this_ptr);
-
- text->removeTextField();
-
- LOG_ONCE(log_debug("TextField.removeTextField() TESTING"));
-
- return as_value();
-}
-
-
-/// This is called for 'new TextField()' only
-as_value
-textfield_ctor(const fn_call& fn)
-{
-
- VM& vm = fn.getVM();
-
- as_object* proto = getTextFieldInterface(vm);
-
- as_object* obj = 0;
-
- if ( vm.getSWFVersion() < 9 )
- {
- // We should attach more properties to the prototype on first
- // instantiation.
- // TODO: this also attaches properties to the SWF5 prototype but makes
- // them invisible with prop flags. Is this correct?
- attachPrototypeProperties(*proto);
-
- obj = new as_object(proto);
- }
- else
- {
- rect nullRect;
- obj = new TextField(0, nullRect);
- }
-
- return as_value(obj);
-}
-
-
-void
-attachTextFieldInterface(as_object& o)
-{
- boost::intrusive_ptr<builtin_function> getset;
-
- // TextField is an AsBroadcaster
- AsBroadcaster::initialize(o);
-
- int propFlags = as_prop_flags::dontDelete
- |as_prop_flags::dontEnum
- |as_prop_flags::readOnly
- |as_prop_flags::isProtected;
-
- // Parent seems to not be a normal property
- getset = new builtin_function(&DisplayObject::parent_getset, NULL);
- o.init_property(NSV::PROP_uPARENT, *getset, *getset);
-
- // Target seems to not be a normal property
- getset = new builtin_function(&DisplayObject::target_getset, NULL);
- o.init_property(NSV::PROP_uTARGET, *getset, *getset);
-
- // _name should be a property of the instance, not the prototype
- getset = new builtin_function(&DisplayObject::name_getset, NULL);
- o.init_property(NSV::PROP_uNAME, *getset, *getset);
-
- o.init_property(NSV::PROP_uXMOUSE,
- DisplayObject::xmouse_get, DisplayObject::xmouse_get, propFlags);
- o.init_property(NSV::PROP_uYMOUSE,
- DisplayObject::ymouse_get, DisplayObject::ymouse_get, propFlags);
- o.init_property(NSV::PROP_uHIGHQUALITY,
- DisplayObject::highquality, DisplayObject::highquality);
- o.init_property(NSV::PROP_uQUALITY,
- DisplayObject::quality, DisplayObject::quality);
- o.init_property(NSV::PROP_uXSCALE,
- DisplayObject::xscale_getset, DisplayObject::xscale_getset);
- o.init_property(NSV::PROP_uYSCALE,
- DisplayObject::yscale_getset, DisplayObject::yscale_getset);
-
- // Standard flags.
- const int flags = as_prop_flags::dontDelete
- |as_prop_flags::dontEnum;
-
- // SWF6 or higher
- const int swf6Flags = flags | as_prop_flags::onlySWF6Up;
-
- o.init_member("setTextFormat",
- new builtin_function(textfield_setTextFormat), swf6Flags);
- o.init_member("getTextFormat",
- new builtin_function(textfield_getTextFormat), swf6Flags);
- o.init_member("setNewTextFormat",
- new builtin_function(textfield_setNewTextFormat), swf6Flags);
- o.init_member("getNewTextFormat",
- new builtin_function(textfield_getNewTextFormat), swf6Flags);
- o.init_member("getNewTextFormat",
- new builtin_function(textfield_getNewTextFormat), swf6Flags);
- o.init_member("getDepth",
- new builtin_function(textfield_getDepth), swf6Flags);
- o.init_member("removeTextField",
- new builtin_function(textfield_removeTextField), swf6Flags);
- o.init_member("replaceSel",
- new builtin_function(textfield_replaceSel), swf6Flags);
-
- // SWF7 or higher
- const int swf7Flags = flags | as_prop_flags::onlySWF7Up;
-
- o.init_member("replaceText",
- new builtin_function(textfield_replaceText), swf7Flags);
-
-}
-
-void
-attachTextFieldStaticMembers(as_object& o)
-{
- // Standard flags.
- const int flags = as_prop_flags::dontDelete
- |as_prop_flags::dontEnum;
-
- // SWF6 or higher
- const int swf6Flags = flags | as_prop_flags::onlySWF6Up;
-
- o.init_member("getFontList",
- new builtin_function(textfield_getFontList), swf6Flags);
-
-}
-
-/// This is called when a prototype should be added
-//
-/// @note This is called at different times, depending on the version.
-/// For SWF5 it is called only on first instantiation. For SWF6 it
-/// is called at the registration of _global.TextField.
-as_object*
-getTextFieldInterface(VM& vm)
-{
- static boost::intrusive_ptr<as_object> proto;
-
- if ( proto == NULL )
- {
- if (vm.getSWFVersion() < 6) {
- /// The prototype for SWF5 is a simple as_object without
- /// toString() or valueOf().
- proto = new as_object();
- vm.addStatic(proto.get());
- }
- else {
- proto = new as_object(getObjectInterface());
- vm.addStatic(proto.get());
- attachTextFieldInterface(*proto);
- }
-
- }
- return proto.get();
-}
-
-} // anonymous namespace
-
-} // namespace gnash
-
-
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:
-
=== removed file 'libcore/TextField.h'
--- a/libcore/TextField.h 2009-04-14 11:26:23 +0000
+++ b/libcore/TextField.h 1970-01-01 00:00:00 +0000
@@ -1,670 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-#ifndef GNASH_TEXTFIELD_H
-#define GNASH_TEXTFIELD_H
-
-#include "InteractiveObject.h" // for inheritance
-#include "styles.h" // for line_style
-#include "fill_style.h"
-#include "Range2d.h"
-#include "rect.h" // for inlines
-#include "Font.h" // for visibility of font add_ref/drop_ref
-
-// Forward declarations
-namespace gnash {
- namespace SWF {
- class DefineEditTextTag;
- class TextRecord;
- }
-}
-
-namespace gnash {
-
-/// An instance of a DefineEditTextTag
-class TextField : public InteractiveObject
-{
-
-public:
-
- /// Text alignment values
- enum TextAlignment
- {
- ALIGN_LEFT = 0,
- ALIGN_RIGHT,
- ALIGN_CENTER,
- ALIGN_JUSTIFY
- };
-
- /// Possible autoSize values
- enum AutoSizeValue {
-
- /// Do not automatically resize TextField as text grow/shrink
- autoSizeNone,
-
- /// Expand TextField, anchor the top-left side
- autoSizeLeft,
-
- /// Expand TextField, anchor the horizontal center
- autoSizeCenter,
-
- /// Expand TextField, anchor the top-right side
- autoSizeRight
- };
-
- /// Possible type values
- enum TypeValue {
-
- /// Invalid value
- typeInvalid,
-
- /// Do not accept input, text is only changed by variable name
- /// or assigning to the .text member
- typeDynamic,
-
- /// Accept user input
- typeInput
- };
-
- /// Constructs a TextField as specified in a DefineEditText tag.
- TextField(DisplayObject* parent, const SWF::DefineEditTextTag& def, int
id);
-
- /// Constructs a TextField with default values and the specified bounds.
- //
- /// Notably, the default textHeight is 12pt (240 twips).
- TextField(DisplayObject* parent, const rect& bounds);
-
- ~TextField();
-
- // TODO: should this return isSelectable() ?
- bool mouseEnabled() const { return true; }
-
- InteractiveObject* topmostMouseEntity(boost::int32_t x,
- boost::int32_t y);
-
- // Text fields need to handle cxform specially
- virtual cxform get_world_cxform() const;
-
- bool wantsInstanceName() const
- {
- return true; // text fields can be referenced
- }
-
- bool on_event(const event_id& id);
-
- const std::string& getVariableName() const
- {
- return _variable_name;
- }
-
- /// Set the name of a variable associated to this
- /// TextField's displayed text.
- //
- /// Calling this function will override any previous
- /// setting for the variable name.
- ///
- void set_variable_name(const std::string& newname);
-
- /// \brief Set our text to the given string by effect of an update of a
- /// registered variable name
- //
- /// This call only updates the text and is only meant to be called
- /// by ourselves or by MovieClip when a registered TextVariable is
- /// updated.
- void updateText(const std::string& s);
-
- /// Return value of our text.
- std::string get_text_value() const;
-
- /// Return true if text is defined
- bool getTextDefined() const { return _textDefined; }
-
- size_t getCaretIndex() const {
- return m_cursor;
- }
-
- const std::pair<size_t, size_t>& getSelection() const {
- return _selection;
- }
-
- /// Replace the current selection with the new text.
- void replaceSelection(const std::string& replace);
-
- /// Set the current selection
- //
- /// @param start The index of the beginning of the selection.
- /// @param end The index of the end of the selection.
- //
- /// If start is greater than end, the values are swapped, ensuring
- /// end is never less than start.
- void setSelection(int start, int end);
-
- /// We have a "text" member.
- bool set_member(string_table::key name, const as_value& val,
- string_table::key nsname = 0, bool ifFound=false);
-
- bool get_member(string_table::key name, as_value* val,
- string_table::key nsname = 0);
-
- /// Draw the dynamic string.
- void display();
-
- void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
-
- virtual rect getBounds() const
- {
- return _bounds;
- }
-
- // See dox in DisplayObject.h
- bool pointInShape(boost::int32_t x, boost::int32_t y) const;
-
- /// Return true if the 'background' should be drawn
- bool getDrawBackground() const;
-
- /// Specify wheter to draw the background
- void setDrawBackground(bool draw);
-
- /// Return color of the background
- rgba getBackgroundColor() const;
-
- /// Set color of the background
- //
- /// Use setDrawBackground to actually use this value.
- ///
- void setBackgroundColor(const rgba& col);
-
- /// Return true if this TextField should have it's border visible
- bool getDrawBorder() const;
-
- /// Specify wheter to draw the border
- void setDrawBorder(bool draw);
-
- /// Return color of the border
- rgba getBorderColor() const;
-
- /// Set color of the border
- //
- /// Use setDrawBorder to actually use this value.
- ///
- void setBorderColor(const rgba& col);
-
- /// Return color of the text
- const rgba& getTextColor() const
- {
- return _textColor;
- }
-
- /// Set color of the text
- void setTextColor(const rgba& col);
-
- /// \brief
- /// Return true if this TextField should use embedded font glyphs,
- /// false if it should use device font glyphs
- bool getEmbedFonts() const {
- return _embedFonts;
- }
-
- /// Get the current maxChars setting of the TextField
- boost::int32_t maxChars() const {
- return _maxChars;
- }
-
- /// Set the current maxChars setting of the TextField
- void maxChars(boost::int32_t max) {
- _maxChars = max;
- }
-
- /// Get the current multiline setting of the TextField
- bool multiline() const {
- return _multiline;
- }
-
- /// Set the current multiline setting of the TextField
- void multiline(bool b) {
- _multiline = b;
- }
-
- /// Get the current password setting of the TextField
- bool password() const {
- return _password;
- }
-
- /// Set the current password setting of the TextField
- void password(bool b) {
- _password = b;
- }
- /// \brief
- /// Set whether this TextField should use embedded font glyphs,
- /// or use device font glyphs
- //
- /// @param use
- void setEmbedFonts(bool use);
-
- /// Get autoSize value
- AutoSizeValue getAutoSize() const
- {
- return _autoSize;
- }
-
- /// Return text TextAlignment
- TextAlignment getTextAlignment();
-
- /// Set autoSize value
- //
- /// @param val
- /// The AutoSizeValue to use
- ///
- void setAutoSize(AutoSizeValue val);
-
- /// Parse autoSize string value
- //
- /// @param val
- /// Auto size value as a string (one of none, left, center, right)
- ///
- /// @return an AutoSizeValue identifier. autoSizeNone if invalid
- ///
- static AutoSizeValue parseAutoSizeValue(const std::string& val);
-
- /// Return autoSize value as a string
- //
- /// @param val
- /// Auto size value
- ///
- /// @return a C-string representation of the autoSize value.
- /// The returns is *never* NULL.
- ///
- static const char* autoSizeValueName(AutoSizeValue val);
-
- /// Set type (input or dynamic)
- //
- /// @param val
- /// The TypeValue to use, no-op if typeInvalid.
- ///
- void setType(TypeValue val) { if (val != typeInvalid) _type=val; }
-
- /// Get type (input, dynamic or invalid)
- TypeValue getType() const
- {
- return _type;
- }
-
- /// Return true if this TextField is read-only
- bool isReadOnly() const { return _type != typeInput; }
-
- /// Parse type string value
- //
- /// @param val
- /// Type value as a string (one of input or dynamic)
- ///
- /// @return an TypeValue identifier. typeInvalid if invalid.
- ///
- static TypeValue parseTypeValue(const std::string& val);
-
- /// Return type value as a string
- //
- /// @param val
- /// Type value (enum)
- ///
- /// @return a C-string representation of the type value.
- /// The returns is *never* NULL.
- ///
- static const char* typeValueName(TypeValue val);
-
- /// \brief
- /// Return true if text should continue to next available line
- /// when hitting end of bounding box.
- ///
- bool doWordWrap() const {
- return _wordWrap;
- }
-
- /// Set wordWrap parameter
- //
- /// @param on
- /// If true text hitting bounding box limits will continue
- /// to next line.
- /// If false, either text will be truncated or bounding box
- /// expanded, depending on autoSize (see getAutoSize)
- ///
- void setWordWrap(bool on);
-
- /// \brief
- /// Return true if HTML markup in text should be rendered.
- ///
- bool doHtml() const {
- return _html;
- }
-
- /// Set html parameter
- //
- /// @param on
- /// If true HTML tags in the text will be parsed and rendered
- void setHtml(bool on) {
- _html = on;
- }
-
- /// Return true if the TextField text is selectable
- bool isSelectable() const
- {
- return _selectable;
- }
-
- /// Set 'selectable' parameter
- void setSelectable(bool v)
- {
- _selectable = v;
- }
-
- // See DisplayObject::isActiveTextField
- virtual bool isSelectableTextField() const
- {
- return isSelectable();
- }
-
- /// Remove this textfield from the stage
- //
- /// This is to implement TextField.removeTextField, will
- /// basically forward the request to its parent.
- /// Eventually this and MovieClip::removeMovieClip
- /// will be merged in a single function to be later used
- /// also for AS3 removeChild().
- ///
- void removeTextField();
-
- /// Set our font, return previously set one.
- //
- /// @param newfont
- /// Will be stored in an intrusive_ptr
- ///
- boost::intrusive_ptr<const Font> setFont(
- boost::intrusive_ptr<const Font> newfont);
-
- const Font* getFont() { return _font.get(); }
-
- boost::uint16_t getFontHeight() const
- {
- return _fontHeight;
- }
-
- void setFontHeight(boost::uint16_t h);
-
- boost::uint16_t getLeftMargin() const
- {
- return _leftMargin;
- }
-
- void setLeftMargin(boost::uint16_t h);
-
- boost::uint16_t getRightMargin() const
- {
- return _rightMargin;
- }
-
- void setRightMargin(boost::uint16_t h);
-
- boost::uint16_t getIndent() const
- {
- return _indent;
- }
-
- void setIndent(boost::uint16_t h);
-
- boost::uint16_t getBlockIndent() const
- {
- return _blockIndent;
- }
-
- void setBlockIndent(boost::uint16_t h);
-
- TextAlignment getAlignment() const
- {
- return _alignment;
- }
-
- void setAlignment(TextAlignment h);
-
- boost::uint16_t getLeading() const
- {
- return _leading;
- }
-
- void setLeading(boost::uint16_t h);
-
- bool getUnderlined() const
- {
- return _underlined;
- }
-
- void setUnderlined(bool v);
-
- const rect& getTextBoundingBox() const
- {
- return m_text_bounding_box;
- }
-
- /// Set our text to the given string.
- //
- /// This function will also update any registered variable
- ///
- void setTextValue(const std::wstring& wstr);
-
-protected:
-
- /// Mark reachable reosurces (for GC)
- //
- /// Reachable resources are:
- /// - The font being used (m_font)
- /// - Our definition
- /// - Common DisplayObject resources
- ///
- void markReachableResources() const;
-
-private:
-
- void init();
-
- /// \brief Set our text to the given string by effect of an update of a
- /// registered variable name
- //
- /// This call only updates the text and is only meant to be called
- /// by ourselves or by MovieClip when a registered TextVariable is
- /// updated.
- void updateText(const std::wstring& s);
-
- void insertTab(SWF::TextRecord& rec, boost::int32_t& x, float scale);
-
- /// What happens when setFocus() is called on this TextField.
- //
- /// @return true if focus was set. A TextField can always receive focus,
- /// so this always returns true.
- virtual bool handleFocus();
-
- /// Kill focus
- virtual void killFocus();
-
- /// Call this function when willing to invoke the onChanged event
handler
- void onChanged();
-
- /// Reset our text bounding box to the given point.
- void reset_bounding_box(boost::int32_t x, boost::int32_t y)
- {
- m_text_bounding_box.set_to_point(x, y);
- }
-
- /// Convert the DisplayObjects in _text into a series of
- /// text_glyph_records to be rendered.
- void format_text();
-
- /// Extracts an HTML tag.
- ///
- /// @param tag This string is filled with the extracted HTML tag.
- /// @param it An iterator pointing to the first DisplayObject of the
- /// HTML tag. It is left pointing to the DisplayObject
after the
- /// closing tag or the end of the string.
- /// @param e An iterator pointing to the end of the string.
- /// @return Whether the tag is complete or not (i.e. whether a '>'
- /// was found).
- bool parseHTML(std::wstring& tag, std::wstring::const_iterator& it,
- const std::wstring::const_iterator& e) const;
-
- /// Does LEFT/CENTER/RIGHT alignment on the records in
- /// m_text_glyph_records[], starting with
- /// last_line_start_record and going through the end of
- /// m_text_glyph_records.
- float align_line(TextAlignment align, int last_line_start_record, float
x);
-
- /// Associate a variable to the text of this DisplayObject
- //
- /// Setting the associated variable actually changes the
- /// displayed text. Getting the variable would return the
- /// displayed text.
- ///
- /// If the given variable already exist use it to set
- /// current text before overriding it.
- ///
- /// Since the variable target may be undefined at time
- /// of instantiation of this EditText DisplayObject, the
- /// class keeps track of wheter it succeeded registering
- /// the variable and this function will do nothing in this
- /// case. Thus it is safe to call it multiple time, using
- /// an as-needed policy (will be called from get_text_value and
- /// display)
- ///
- void registerTextVariable();
-
- typedef std::pair<as_object*, string_table::key> VariableRef;
-
- /// \brief
- /// Parse the given variable name
- /// into sprite and a string_table::key components
- ///
- VariableRef parseTextVariableRef(const std::string& variableName) const;
-
- /// The immutable definition of our TextField
- //
- /// This is NULL for dynamic TextFields.
- boost::intrusive_ptr<const SWF::DefineEditTextTag> _tag;
-
- /// The actual text.
- //
- /// Because we have to deal with non-ascii DisplayObjects (129-255), this
- /// is a wide string; the cursor position and the position within the
- /// string are then the same, which makes manipulating the string much
- /// easier.
- std::wstring _text;
-
- /// This flag will be true as soon as the TextField
- /// is assigned a text value. Only way to be false is
- /// when definition has the hasText flag set to false
- /// and no actionscript added text.
- bool _textDefined;
-
- /// bounds of dynamic text, as laid out
- rect m_text_bounding_box;
-
- typedef std::vector<SWF::TextRecord> TextRecords;
- TextRecords _textRecords;
- bool _underlined;
-
- boost::uint16_t _leading;
-
- TextAlignment _alignment;
-
- boost::uint16_t _indent;
-
- /// Indentation for every line (including the ones created by
- /// effect of a word-wrap.
- boost::uint16_t _blockIndent;
-
- boost::uint16_t _leftMargin;
-
- boost::uint16_t _rightMargin;
-
- boost::uint16_t _fontHeight;
-
- boost::intrusive_ptr<const Font> _font;
-
- bool m_has_focus;
- size_t m_cursor;
- void show_cursor(const SWFMatrix& mat);
- float m_xcursor;
- float m_ycursor;
-
- /// Corresponds to the multiline property.
- bool _multiline;
-
- /// Corresponds to the password property.
- bool _password;
-
- /// Corresponds to the maxChars property.
- boost::int32_t _maxChars;
- /// The flag keeping status of TextVariable registration
- //
- /// It will be set to true if there's no need to register
- /// a text variable (ie. non-specified in the SWF)
- ///
- bool _text_variable_registered;
-
- /// The text variable name
- //
- /// This is stored here, and not just in the definition,
- /// because it can be changed programmatically, by setting
- /// 'TextFields.variable'
- std::string _variable_name;
-
- bool _drawBackground;
-
- rgba _backgroundColor;
-
- bool _drawBorder;
-
- rgba _borderColor;
-
- rgba _textColor;
-
- bool _embedFonts;
-
- bool _wordWrap;
-
- bool _html;
-
- bool _selectable;
-
- AutoSizeValue _autoSize;
-
- TypeValue _type;
-
- /// Area in which the text is drawn.
- //
- /// This area encloses all the text, can be automatically
- /// extended to fit text or hide text overflowing it.
- /// See the setAutoSize() method to change that.
- ///
- rect _bounds;
-
- /// Represents the selected part of the text. The second element must
- /// never be less than the first.
- std::pair<size_t, size_t> _selection;
-};
-
-/// Initialize the global TextField class
-void textfield_class_init(as_object& global);
-
-} // namespace gnash
-
-#endif
=== modified file 'libcore/asobj/Global.cpp'
--- a/libcore/asobj/Global.cpp 2009-06-08 22:15:34 +0000
+++ b/libcore/asobj/Global.cpp 2009-06-08 22:24:55 +0000
@@ -61,7 +61,7 @@
#include "Timers.h"
#include "URL.h" // for URL::encode and URL::decode (escape/unescape)
#include "builtin_function.h"
-#include "TextField.h"
+#include "flash/text/TextField_as.h"
#include "rc.h"
#include "ClassHierarchy.h"
#include "namedStrings.h"
=== modified file 'libcore/asobj/Selection_as.cpp'
--- a/libcore/asobj/Selection_as.cpp 2009-04-03 09:18:40 +0000
+++ b/libcore/asobj/Selection_as.cpp 2009-06-08 22:24:55 +0000
@@ -29,7 +29,7 @@
#include "builtin_function.h" // need builtin_function
#include "Object.h" // for getObjectInterface
#include "AsBroadcaster.h"
-#include "TextField.h"
+#include "text/TextField_as.h"
// For getting and setting focus
#include "VM.h"
@@ -120,7 +120,7 @@
movie_root& mr = ptr->getVM().getRoot();
DisplayObject* focus = mr.getFocus().get();
- TextField* tf = dynamic_cast<TextField*>(focus);
+ TextField_as* tf = dynamic_cast<TextField_as*>(focus);
if (!tf) return as_value(-1);
@@ -142,7 +142,7 @@
movie_root& mr = ptr->getVM().getRoot();
DisplayObject* focus = mr.getFocus().get();
- TextField* tf = dynamic_cast<TextField*>(focus);
+ TextField_as* tf = dynamic_cast<TextField_as*>(focus);
if (!tf) return as_value(-1);
@@ -158,7 +158,7 @@
movie_root& mr = ptr->getVM().getRoot();
DisplayObject* focus = mr.getFocus().get();
- TextField* tf = dynamic_cast<TextField*>(focus);
+ TextField_as* tf = dynamic_cast<TextField_as*>(focus);
if (!tf) return as_value(-1);
@@ -257,7 +257,7 @@
movie_root& mr = ptr->getVM().getRoot();
DisplayObject* focus = mr.getFocus().get();
- TextField* tf = dynamic_cast<TextField*>(focus);
+ TextField_as* tf = dynamic_cast<TextField_as*>(focus);
if (!tf) return as_value();
=== modified file 'libcore/asobj/flash/text/TextField_as.cpp'
--- a/libcore/asobj/flash/text/TextField_as.cpp 2009-05-28 17:11:27 +0000
+++ b/libcore/asobj/flash/text/TextField_as.cpp 2009-06-08 22:24:55 +0000
@@ -22,16 +22,94 @@
#endif
#include "text/TextField_as.h"
-#include "log.h"
#include "fn_call.h"
#include "smart_ptr.h" // for boost intrusive_ptr
-#include "builtin_function.h" // need builtin_function
#include "GnashException.h" // for ActionException
+#include "utf8.h"
+#include "log.h"
+#include "swf/DefineEditTextTag.h"
+#include "render.h"
+#include "movie_definition.h" // to extract version info
+#include "MovieClip.h"
+#include "ui/Keyboard_as.h" // for keyboard events
+#include "movie_root.h" // for killing focus
+#include "as_environment.h" // for parse_path
+#include "action.h" // for as_standard_member enum
+#include "VM.h"
+#include "builtin_function.h" // for getter/setter properties
+#include "Font.h" // for using the _font member
+#include "fontlib.h" // for searching or adding fonts the _font member
+#include "Object.h" // for getObjectInterface
+#include "namedStrings.h"
+#include "Array_as.h" // for _listeners construction
+#include "AsBroadcaster.h" // for initializing self as a broadcaster
+#include "StringPredicates.h"
+#include "text/TextFormat_as.h" // for getTextFormat/setTextFormat
+#include "GnashKey.h" // key::code
+#include "TextRecord.h"
+#include "Point2d.h"
+#include "GnashNumeric.h"
+
+#include <algorithm> // std::min
+#include <string>
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
+
+#define PADDING_TWIPS 40
namespace gnash {
// Forward declarations
namespace {
+ as_object* getTextFieldInterface(VM& vm);
+ void attachPrototypeProperties(as_object& proto);
+ void attachTextFieldStaticMembers(as_object& o);
+
+ 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_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);
+
+ //AS3 methods
+ as_value textfield_antiAliasType(const fn_call& fn);
+ as_value textfield_sharpness(const fn_call& fn);
+ as_value textfield_gridFitType(const fn_call& fn);
+ as_value textfield_thickness(const fn_call& fn);
+ as_value textfield_condenseWhite(const fn_call& fn);
+ as_value textfield_bottomScrollV(const fn_call& fn);
as_value textfield_getCharBoundaries(const fn_call& fn);
as_value textfield_getCharIndexAtPoint(const fn_call& fn);
as_value textfield_getFirstCharInParagraph(const fn_call& fn);
@@ -45,48 +123,2855 @@
as_value textfield_getParagraphLength(const fn_call& fn);
as_value textfield_getTextFormat(const fn_call& fn);
as_value textfield_replaceSelectedText(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_mouseWheelEnabled(const fn_call& fn);
+ //AS3 events
as_value textfield_change(const fn_call& fn);
as_value textfield_link(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);
- as_object* getTextFieldInterface();
-
-}
-
-class TextField_as : public as_object
-{
-
-public:
-
- TextField_as()
- :
- as_object(getTextFieldInterface())
- {}
-};
-
-// extern (used by Global.cpp)
-void textfield_class_init(as_object& global)
-{
- static boost::intrusive_ptr<builtin_function> cl;
-
- if (!cl) {
- cl = new builtin_function(&textfield_ctor, getTextFieldInterface());
- attachTextFieldStaticInterface(*cl);
+}
+
+TextField_as::TextField_as(DisplayObject* parent, const
SWF::DefineEditTextTag& def,
+ int id)
+ :
+ InteractiveObject(parent, id),
+ _tag(&def),
+ _textDefined(def.hasText()),
+ _underlined(false),
+ _leading(def.leading()),
+ _alignment(def.alignment()),
+ _indent(def.indent()),
+ _blockIndent(0),
+ _leftMargin(def.leftMargin()),
+ _rightMargin(def.rightMargin()),
+ _fontHeight(def.textHeight()),
+ _font(0),
+ m_has_focus(false),
+ m_cursor(0u),
+ m_xcursor(0.0f),
+ m_ycursor(0.0f),
+ _multiline(def.multiline()),
+ _password(def.password()),
+ _maxChars(def.maxChars()),
+ _text_variable_registered(false),
+ _variable_name(def.variableName()),
+ _drawBackground(def.border()),
+ _backgroundColor(255,255,255,255),
+ _drawBorder(def.border()),
+ _borderColor(0,0,0,255),
+ _textColor(def.color()),
+ _embedFonts(def.getUseEmbeddedGlyphs()),
+ _wordWrap(def.wordWrap()),
+ _html(def.html()),
+ _selectable(!def.noSelect()),
+ _autoSize(autoSizeNone),
+ _type(def.readOnly() ? typeDynamic : typeInput),
+ _bounds(def.bounds()),
+ _selection(0, 0)
+{
+
+ // WARNING! remember to set the font *before* setting text value!
+ boost::intrusive_ptr<const Font> f = def.getFont();
+ if (!f) f = fontlib::get_default_font();
+ setFont(f);
+
+ int version = parent->getVM().getSWFVersion();
+
+ // set default text *before* calling registerTextVariable
+ // (if the textvariable already exist and has a value
+ // the text will be replaced with it)
+ if (_textDefined)
+ {
+ setTextValue(utf8::decodeCanonicalString(def.defaultText(), version));
+ }
+}
+
+TextField_as::TextField_as(DisplayObject* parent, const rect& bounds)
+ :
+ // the id trick is to fool assertions in DisplayObject ctor
+ InteractiveObject(parent, parent ? 0 : -1),
+ _textDefined(false),
+ _underlined(false),
+ _leading(0),
+ _alignment(ALIGN_LEFT),
+ _indent(0),
+ _blockIndent(0),
+ _leftMargin(0),
+ _rightMargin(0),
+ _fontHeight(12 * 20),
+ _font(0),
+ m_has_focus(false),
+ m_cursor(0u),
+ m_xcursor(0.0f),
+ m_ycursor(0.0f),
+ _multiline(false),
+ _password(false),
+ _maxChars(0),
+ _text_variable_registered(false),
+ _drawBackground(false),
+ _backgroundColor(255,255,255,255),
+ _drawBorder(false),
+ _borderColor(0, 0, 0, 255),
+ _textColor(0, 0, 0, 255),
+ _embedFonts(false), // ?
+ _wordWrap(false),
+ _html(false),
+ _selectable(true),
+ _autoSize(autoSizeNone),
+ _type(typeDynamic),
+ _bounds(bounds),
+ _selection(0, 0)
+{
+ // Use the default font (Times New Roman for Windows, Times for Mac
+ // according to docs. They don't say what it is for Linux.
+ boost::intrusive_ptr<const Font> f = fontlib::get_default_font();
+ setFont(f);
+}
+
+TextField_as::~TextField_as()
+{
+}
+
+/// 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_as::init(as_object& global)
+{
+ static boost::intrusive_ptr<builtin_function> cl = NULL;
+
+ if (!cl)
+ {
+ VM& vm = global.getVM();
+
+ if (vm.getSWFVersion() < 6) {
+ /// Version 5 or less: no initial prototype
+ cl = new builtin_function(&textfield_ctor, 0);
+ }
+ else {
+ /// Version 6 upward: limited initial prototype
+ as_object* iface = getTextFieldInterface(vm);
+ cl = new builtin_function(&textfield_ctor, iface);
+ }
+
+ vm.addStatic(cl.get());
+
+ // replicate static members to class, to be able to access
+ // all methods as static functions
+ attachTextFieldStaticMembers(*cl);
+
}
// Register _global.TextField
global.init_member("TextField", cl.get());
}
+void
+TextField_as::removeTextField()
+{
+ int depth = get_depth();
+ if ( depth < 0 || depth > 1048575 )
+ {
+ //IF_VERBOSE_ASCODING_ERRORS(
+ log_debug(_("CHECKME: removeTextField(%s): TextField depth (%d) "
+ "out of the 'dynamic' zone [0..1048575], won't remove"),
+ getTarget(), depth);
+ //);
+ return;
+ }
+
+ DisplayObject* parent = get_parent();
+ assert(parent); // every TextField must have a parent, right ?
+
+ MovieClip* parentSprite = parent->to_movie();
+
+ if (!parentSprite)
+ {
+ log_error("FIXME: attempt to remove a TextField being a child of a %s",
+ typeName(*parent));
+ return;
+ }
+
+ // second argument is arbitrary, see comments above
+ // the function declaration in MovieClip.h
+ parentSprite->remove_display_object(depth, 0);
+}
+
+void
+TextField_as::show_cursor(const SWFMatrix& mat)
+{
+ boost::uint16_t x = static_cast<boost::uint16_t>(m_xcursor);
+ boost::uint16_t y = static_cast<boost::uint16_t>(m_ycursor);
+ boost::uint16_t h = getFontHeight();
+
+ const std::vector<point> box = boost::assign::list_of
+ (point(x, y))
+ (point(x, y + h));
+
+ render::drawLine(box, rgba(0,0,0,255), mat);
+}
+
+void
+TextField_as::display()
+{
+
+ registerTextVariable();
+
+ const bool drawBorder = getDrawBorder();
+ const bool drawBackground = getDrawBackground();
+
+ const SWFMatrix& wmat = getWorldMatrix();
+
+ if ((drawBorder || drawBackground) && !_bounds.is_null())
+ {
+
+ std::vector<point> coords(4);
+
+ boost::int32_t xmin = _bounds.get_x_min();
+ boost::int32_t xmax = _bounds.get_x_max();
+ boost::int32_t ymin = _bounds.get_y_min();
+ boost::int32_t ymax = _bounds.get_y_max();
+
+ coords[0].setTo(xmin, ymin);
+ coords[1].setTo(xmax, ymin);
+ coords[2].setTo(xmax, ymax);
+ coords[3].setTo(xmin, ymax);
+
+ rgba borderColor = drawBorder ? getBorderColor() : rgba(0,0,0,0);
+ rgba backgroundColor = drawBackground ? getBackgroundColor() :
+ rgba(0,0,0,0);
+
+ cxform cx = get_world_cxform();
+
+ if (drawBorder) borderColor = cx.transform(borderColor);
+
+ if (drawBackground) backgroundColor = cx.transform(backgroundColor);
+
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("rendering a Pol composed by corners %s", _bounds);
+#endif
+
+ render::draw_poly(&coords.front(), 4, backgroundColor,
+ borderColor, wmat, true);
+
+ }
+
+ // Draw our actual text.
+ // Using a SWFMatrix to translate to def bounds seems an hack to me.
+ // A cleaner implementation is likely correctly setting the
+ // _xOffset and _yOffset memebers in glyph records.
+ // Anyway, see bug #17954 for a testcase.
+ SWFMatrix m = getWorldMatrix();
+
+ if (!_bounds.is_null()) {
+ m.concatenate_translation(_bounds.get_x_min(), _bounds.get_y_min());
+ }
+
+ SWF::TextRecord::displayRecords(m, get_world_cxform(), _textRecords,
+ _embedFonts);
+
+ if (m_has_focus) show_cursor(wmat);
+
+ clear_invalidated();
+}
+
+void
+TextField_as::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool force)
+{
+ if (!force && !m_invalidated) return; // no need to redraw
+
+ ranges.add(m_old_invalidated_ranges);
+
+ const SWFMatrix& wm = getWorldMatrix();
+
+ rect bounds = getBounds();
+ bounds.expand_to_rect(m_text_bounding_box);
+ wm.transform(bounds);
+ ranges.add(bounds.getRange());
+}
+
+void
+TextField_as::replaceSelection(const std::string& replace)
+{
+
+ const int version = _vm.getSWFVersion();
+ const std::wstring& wstr = utf8::decodeCanonicalString(replace, version);
+
+ const size_t start = _selection.first;
+ const size_t replaceLength = wstr.size();
+
+ _text.replace(start, _selection.second - start, wstr);
+ _selection = std::make_pair(start + replaceLength, start + replaceLength);
+}
+
+void
+TextField_as::setSelection(int start, int end)
+{
+
+ if (_text.empty()) {
+ _selection = std::make_pair(0, 0);
+ return;
+ }
+
+ const size_t textLength = _text.size();
+
+ if (start < 0) start = 0;
+ else start = std::min<size_t>(start, textLength);
+
+ if (end < 0) end = 0;
+ else end = std::min<size_t>(end, textLength);
+
+ // The cursor position is always set to the end value, even if the
+ // two values are swapped to obtain the selection. Equal values are
+ // fine.
+ m_cursor = end;
+ if (start > end) std::swap(start, end);
+
+ _selection = std::make_pair(start, end);
+}
+
+bool
+TextField_as::on_event(const event_id& ev)
+{
+ if (isReadOnly()) return false;
+
+ switch (ev.id())
+ {
+ case event_id::KEY_PRESS:
+ {
+ if ( getType() != typeInput ) break; // not an input field
+ std::wstring s = _text;
+
+ // id.keyCode is the unique gnash::key::code for a
DisplayObject/key.
+ // The maximum value is about 265, including function keys.
+ // It seems that typing in DisplayObjects outside the Latin-1 set
+ // (256 DisplayObject codes, identical to the first 256 of UTF-8)
+ // is not supported, though a much greater number UTF-8 codes can
be
+ // stored and displayed. See utf.h for more information.
+ // This is a limit on the number of key codes, not on the
+ // capacity of strings.
+ gnash::key::code c = ev.keyCode();
+
+ // maybe _text is changed in ActionScript
+ m_cursor = std::min<size_t>(m_cursor, _text.size());
+
+ switch (c)
+ {
+ case key::BACKSPACE:
+ if (m_cursor > 0)
+ {
+ s.erase(m_cursor - 1, 1);
+ m_cursor--;
+ setTextValue(s);
+ }
+ break;
+
+ case key::DELETEKEY:
+ if (s.size() > m_cursor)
+ {
+ s.erase(m_cursor, 1);
+ setTextValue(s);
+ }
+ break;
+
+ case key::INSERT: // TODO
+ break;
+
+ case key::HOME:
+ case key::PGUP:
+ case key::UP:
+ m_cursor = 0;
+ format_text();
+ break;
+
+ case key::END:
+ case key::PGDN:
+ case key::DOWN:
+ m_cursor = _text.size();
+ format_text();
+ break;
+
+ case key::LEFT:
+ m_cursor = m_cursor > 0 ? m_cursor - 1 : 0;
+ format_text();
+ break;
+
+ case key::RIGHT:
+ m_cursor = m_cursor < _text.size() ? m_cursor + 1 :
+ _text.size();
+ format_text();
+ break;
+
+ default:
+ wchar_t t = static_cast<wchar_t>(
+ gnash::key::codeMap[c][key::ASCII]);
+ if (t != 0)
+ {
+ // Insert one copy of the DisplayObject
+ // at the cursor position.
+ s.insert(m_cursor, 1, t);
+ m_cursor++;
+ }
+ setTextValue(s);
+ break;
+ }
+ onChanged();
+ }
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+InteractiveObject*
+TextField_as::topmostMouseEntity(boost::int32_t x, boost::int32_t y)
+{
+
+ if (!visible()) return 0;
+
+ // shouldn't this be !can_handle_mouse_event() instead ?
+ // not selectable, so don't catch mouse events!
+ if (!_selectable) return 0;
+
+ SWFMatrix m = getMatrix();
+ point p(x, y);
+ m.invert().transform(p);
+
+ if (_bounds.point_test(p.x, p.y)) return this;
+
+ return 0;
+}
+
+void
+TextField_as::updateText(const std::string& str)
+{
+ int version = _vm.getSWFVersion();
+ const std::wstring& wstr = utf8::decodeCanonicalString(str, version);
+ updateText(wstr);
+}
+
+void
+TextField_as::updateText(const std::wstring& wstr)
+{
+ _textDefined = true;
+
+ if (_text == wstr) return;
+
+ set_invalidated();
+
+ _text = wstr;
+ format_text();
+}
+
+void
+TextField_as::setTextValue(const std::wstring& wstr)
+{
+
+ updateText(wstr);
+
+ if ( ! _variable_name.empty() && _text_variable_registered )
+ {
+ // TODO: notify MovieClip if we have a variable name !
+ VariableRef ref = parseTextVariableRef(_variable_name);
+ as_object* tgt = ref.first;
+ if ( tgt )
+ {
+ int version = _vm.getSWFVersion();
+ // we shouldn't truncate, right?
+ tgt->set_member(ref.second, utf8::encodeCanonicalString(wstr,
+ version));
+ }
+ else
+ {
+ // nothing to do (too early ?)
+ log_debug("setTextValue: variable name %s points to a non-existent"
+ " target, I guess we would not be registered if this was "
+ "true, or the sprite we've registered our variable name "
+ "has been unloaded", _variable_name);
+ }
+ }
+}
+
+std::string
+TextField_as::get_text_value() const
+{
+ // we need the const_cast here because registerTextVariable
+ // *might* change our text value, calling the non-const
+ // setTextValue().
+ // This happens if the TextVariable has not been already registered
+ // and during registration comes out to name an existing variable
+ // with a pre-existing value.
+ const_cast<TextField_as*>(this)->registerTextVariable();
+
+ int version = _vm.getSWFVersion();
+
+ return utf8::encodeCanonicalString(_text, version);
+}
+
+bool
+TextField_as::set_member(string_table::key name,
+ const as_value& val, string_table::key nsname, bool ifFound)
+{
+
+ // FIXME: Turn all standard members into getter/setter properties
+ // of the TextField class. See attachTextFieldInterface()
+ // @@ TODO need to inherit basic stuff like _x, _y, _xscale, _yscale etc ?
+
+ switch (name)
+ {
+ default:
+ break;
+ case NSV::PROP_uX:
+ {
+ SWFMatrix m = getMatrix();
+ double x = infinite_to_zero( val.to_number() );
+ m.tx = pixelsToTwips(x);
+ setMatrix(m); // no need to update caches when only changing
translation
+
+ // m_accept_anim_moves = false;
+ return true;
+ }
+ case NSV::PROP_uY:
+ {
+ SWFMatrix m = getMatrix();
+ double y = infinite_to_zero( val.to_number() );
+ m.ty = pixelsToTwips(y);
+ setMatrix(m); // no need to update caches when only changing
translation
+
+ // m_accept_anim_moves = false;
+ return true;
+ }
+ case NSV::PROP_uWIDTH:
+ {
+ double nw = val.to_number();
+ if (!isFinite(nw) )
+ {
+ // might be our fault, see the TODO above
+ // (missing to pass as_environment out..)
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Attempt to set TextField._width to %g"), nw);
+ );
+ return true;
+ }
+
+ if ( nw < 0 )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Attempt to set TextField._width to a "
+ "negative number: %g, toggling sign"), nw);
+ );
+ nw = -nw;
+ }
+
+ if ( _bounds.width() == pixelsToTwips(nw) )
+ {
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("TextField width already == %g, nothing to do to "
+ "change it", nw);
+#endif
+ return true; // nothing to do
+ }
+ if ( _bounds.is_null() )
+ {
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("NULL TextField bounds : %s", _bounds);
+#endif
+ return true;
+ }
+
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("Chaging TextField width to %g", nw);
+#endif
+
+ set_invalidated();
+
+ // Modify TextField drawing rectangle
+ // TODO: check which anchor point we should use !
+ boost::int32_t xmin = _bounds.get_x_min();
+ boost::int32_t ymin = _bounds.get_y_min();
+ boost::int32_t ymax = _bounds.get_y_max();
+ boost::int32_t xmax = xmin + pixelsToTwips(nw);
+
+ assert(xmin <= xmax);
+ _bounds.set_to_rect(xmin, ymin, xmax, ymax);
+ assert( _bounds.width() == pixelsToTwips(nw) );
+
+ // previously truncated text might get visible now
+ // TODO: if nested masks were implemented we would
+ // not need to reformat text here
+ format_text();
+
+ return true;
+ }
+ case NSV::PROP_uHEIGHT:
+ {
+ double nh = val.to_number();
+ if (!isFinite(nh) )
+ {
+ // might be our fault, see the TODO above (missing to pass
+ // as_environment out..)
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Attempt to set TextField._height to %g"), nh);
+ );
+ return true;
+ }
+
+ if ( nh < 0.0f )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("Attempt to set TextField._height to a negative "
+ "number: %g, toggling sign"), nh);
+ );
+ nh = -nh;
+ }
+
+ if ( _bounds.height() == pixelsToTwips(nh) )
+ {
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("TextField height already == %g, nothing to do to "
+ "change it", nh);
+#endif // GNASH_DEBUG_TEXTFIELDS
+ return true; // nothing to do
+ }
+ if ( _bounds.is_null() )
+ {
+ return true;
+ }
+
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("Changing TextField height to %g", nh);
+#endif // GNASH_DEBUG_TEXTFIELDS
+ set_invalidated();
+
+ // Modify TextField drawing rectangle
+ // TODO: check which anchor point we should use !
+ boost::int32_t xmin = _bounds.get_x_min();
+ boost::int32_t xmax = _bounds.get_x_max();
+ boost::int32_t ymin = _bounds.get_y_min();
+ _bounds.set_to_rect(xmin, ymin, xmax, ymin + pixelsToTwips(nh) );
+
+ assert(_bounds.height() == pixelsToTwips(nh));
+
+ // previously truncated text might get visible now
+ // TODO: if nested masks were implemented we would
+ // not need to reformat text here
+ format_text();
+
+ return true;
+ }
+ case NSV::PROP_uVISIBLE:
+ {
+ set_visible(val.to_bool());
+ return true;
+ }
+ case NSV::PROP_uALPHA:
+ {
+ // @@ TODO this should be generic to class DisplayObject!
+ // Arg is in percent.
+ cxform cx = get_cxform();
+ cx.aa = (boost::int16_t)(val.to_number() * 2.56);
+ set_cxform(cx);
+ return true;
+ }
+ // @@ TODO see TextField members in Flash MX docs
+ } // end switch
+
+
+ return as_object::set_member(name, val, nsname, ifFound);
+}
+
+bool
+TextField_as::get_member(string_table::key name, as_value* val,
+ string_table::key nsname)
+{
+ //log_debug("TextField.get_member(%s)", name);
+
+ // FIXME: Turn all standard members into getter/setter properties
+ // of the TextField class. See attachTextFieldInterface()
+
+ switch (name)
+ {
+ default:
+ break;
+ case NSV::PROP_uVISIBLE:
+ {
+ val->set_bool(visible());
+ return true;
+ }
+ case NSV::PROP_uALPHA:
+ {
+ // @@ TODO this should be generic to class DisplayObject!
+ const cxform& cx = get_cxform();
+ val->set_double(cx.aa / 2.56);
+ return true;
+ }
+ case NSV::PROP_uX:
+ {
+ SWFMatrix m = getMatrix();
+ val->set_double(twipsToPixels(m.tx));
+ return true;
+ }
+ case NSV::PROP_uY:
+ {
+ SWFMatrix m = getMatrix();
+ val->set_double(twipsToPixels(m.ty));
+ return true;
+ }
+ case NSV::PROP_uWIDTH:
+ {
+ val->set_double(twipsToPixels(get_width()));
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("Got TextField width == %s", *val);
+#endif // GNASH_DEBUG_TEXTFIELDS
+ return true;
+ }
+ case NSV::PROP_uHEIGHT:
+ {
+ val->set_double(twipsToPixels(get_height()));
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug("Got TextField height == %s", *val);
+#endif // GNASH_DEBUG_TEXTFIELDS
+ return true;
+ }
+ } // end switch
+
+ return as_object::get_member(name, val, nsname);
+
+}
+
+float
+TextField_as::align_line(TextAlignment align,
+ int last_line_start_record, float x)
+{
+
+ float width = _bounds.width();
+ float right_margin = getRightMargin();
+
+ float extra_space = (width - right_margin) - x - PADDING_TWIPS;
+
+ //assert(extra_space >= 0.0f);
+ if (extra_space <= 0.0f)
+ {
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug(_("TextField text doesn't fit in its boundaries: "
+ "width %g, margin %g - nothing to align"),
+ width, right_margin);
+#endif
+ return 0.0f;
+ }
+
+ float shift_right = 0.0f;
+
+ if (align == ALIGN_LEFT)
+ {
+ // Nothing to do; already aligned left.
+ return 0.0f;
+ }
+ else if (align == ALIGN_CENTER)
+ {
+ // Distribute the space evenly on both sides.
+ shift_right = extra_space / 2;
+ }
+ else if (align == ALIGN_RIGHT)
+ {
+ // Shift all the way to the right.
+ shift_right = extra_space;
+ }
+
+ // Shift the beginnings of the records on this line.
+ for (unsigned int i = last_line_start_record; i < _textRecords.size(); ++i)
+ {
+ SWF::TextRecord& rec = _textRecords[i];
+
+ //if ( rec.hasXOffset() ) // why?
+ rec.setXOffset(rec.xOffset() + shift_right);
+ }
+ return shift_right;
+}
+
+boost::intrusive_ptr<const Font>
+TextField_as::setFont(boost::intrusive_ptr<const Font> newfont)
+{
+ if ( newfont == _font ) return _font;
+
+ boost::intrusive_ptr<const Font> oldfont = _font;
+ set_invalidated();
+ _font = newfont;
+ format_text();
+ return oldfont;
+}
+
+void
+TextField_as::insertTab(SWF::TextRecord& rec, boost::int32_t& x, float scale)
+{
+ // tab (ASCII HT)
+ const int space = 32;
+ int index = rec.getFont()->get_glyph_index(space, _embedFonts);
+ if ( index == -1 )
+ {
+ IF_VERBOSE_MALFORMED_SWF (
+ log_error(_("TextField: missing glyph for space char (needed "
+ "for TAB). Make sure DisplayObject shapes for font "
+ "%s are being exported into your SWF file."),
+ rec.getFont()->name());
+ );
+ }
+ else
+ {
+ SWF::TextRecord::GlyphEntry ge;
+ ge.index = index;
+ ge.advance = scale * rec.getFont()->get_advance(index,
+ _embedFonts);
+
+ const int tabstop = 8;
+ rec.addGlyph(ge, tabstop);
+ x += ge.advance * tabstop;
+ }
+}
+
+void
+TextField_as::format_text()
+{
+ _textRecords.clear();
+
+ // nothing more to do if text is empty
+ if ( _text.empty() )
+ {
+ // TODO: should we still reset _bounds if autoSize != autoSizeNone ?
+ // not sure we should...
+ reset_bounding_box(0, 0);
+ return;
+ }
+
+ // See bug #24266
+ const rect& defBounds = _bounds;
+
+ AutoSizeValue autoSize = getAutoSize();
+ if ( autoSize != autoSizeNone )
+ {
+ // define GNASH_DEBUG_TEXT_FORMATTING on top to get useful info
+ //LOG_ONCE( log_debug(_("TextField.autoSize != 'none' TESTING")) );
+
+ // When doing WordWrap we don't want to change
+ // the boundaries. See bug #24348
+ if (! doWordWrap() )
+ {
+ _bounds.set_to_rect(0, 0, 0, 0); // this is correct for 'true'
+ }
+ }
+
+ // Should get info from autoSize too maybe ?
+ TextAlignment textAlignment = getTextAlignment();
+
+ // FIXME: I don't think we should query the definition
+ // to find the appropriate font to use, as ActionScript
+ // code should be able to change the font of a TextField
+ //
+ if (!_font)
+ {
+ log_error(_("No font for TextField!"));
+ return;
+ }
+
+ boost::uint16_t fontHeight = getFontHeight();
+ float scale = fontHeight / (float)_font->unitsPerEM(_embedFonts);
+ float fontDescent = _font->descent() * scale;
+ float fontLeading = _font->leading() * scale;
+ boost::uint16_t leftMargin = getLeftMargin();
+ boost::uint16_t rightMargin = getRightMargin();
+ boost::uint16_t indent = getIndent();
+ boost::uint16_t blockIndent = getBlockIndent();
+ bool underlined = getUnderlined();
+
+ //log_debug("%s: fontDescent:%g, fontLeading:%g, fontHeight:%g, scale:%g",
+ // getTarget(), fontDescent, fontLeading, fontHeight, scale);
+
+ SWF::TextRecord rec; // one to work on
+ rec.setFont(_font.get());
+ rec.setUnderline(underlined);
+ rec.setColor(getTextColor());
+ rec.setXOffset(PADDING_TWIPS +
+ std::max(0, leftMargin + indent + blockIndent));
+ rec.setYOffset(PADDING_TWIPS + fontHeight + (fontLeading - fontDescent));
+ rec.setTextHeight(fontHeight);
+
+ boost::int32_t x = static_cast<boost::int32_t>(rec.xOffset());
+ boost::int32_t y = static_cast<boost::int32_t>(rec.yOffset());
+
+ // Start the bbox at the upper-left corner of the first glyph.
+ reset_bounding_box(x, y - fontDescent + fontHeight);
+
+ float leading = getLeading();
+ leading += fontLeading * scale; // not sure this is correct...
+
+ int last_code = -1; // only used if _embedFonts
+ int last_space_glyph = -1;
+ int last_line_start_record = 0;
+
+ unsigned int idx = 0;
+ m_xcursor = x;
+ m_ycursor = y;
+
+ assert(! _text.empty() );
+
+ boost::uint32_t code = 0;
+
+ // String iterators are very sensitive to
+ // potential changes to the string (to allow for copy-on-write).
+ // So there must be no external changes to the string or
+ // calls to most non-const member functions during this loop.
+ // Especially not c_str() or data().
+ std::wstring::const_iterator it = _text.begin();
+ const std::wstring::const_iterator e = _text.end();
+
+ while (it != e)
+ {
+ code = *it++;
+ if (!code) break;
+
+ if ( _embedFonts )
+ {
+ x += rec.getFont()->get_kerning_adjustment(last_code,
+ static_cast<int>(code)) * scale;
+ last_code = static_cast<int>(code);
+ }
+
+ // Expand the bounding-box to the lower-right corner of each glyph as
+ // we generate it.
+ m_text_bounding_box.expand_to_point(x, y + fontDescent);
+
+ switch (code)
+ {
+ case 27:
+ // Ignore escape
+ break;
+ case 9:
+ insertTab(rec, x, scale);
+ break;
+ case 13:
+ case 10:
+ {
+ // newline.
+
+ // Frigging Flash seems to use '\r' (13) as its
+ // default newline DisplayObject. If we get DOS-style \r\n
+ // sequences, it'll show up as double newlines, so maybe we
+ // need to detect \r\n and treat it as one newline.
+
+ // Close out this stretch of glyphs.
+ _textRecords.push_back(rec);
+ align_line(textAlignment, last_line_start_record, x);
+
+ // Expand bounding box to include last column of text ...
+ if ( _autoSize != autoSizeNone ) {
+ _bounds.expand_to_point(x + PADDING_TWIPS,
+ y + PADDING_TWIPS);
+ }
+
+ // new paragraphs get the indent.
+ x = std::max(0, leftMargin + indent) + PADDING_TWIPS;
+ y += fontHeight + leading;
+
+ // Start a new record on the next line. Other properties of the
+ // TextRecord should be left unchanged.
+ rec.clearGlyphs();
+ rec.setXOffset(x);
+ rec.setYOffset(y);
+
+ last_space_glyph = -1;
+ last_line_start_record = _textRecords.size();
+
+ continue;
+ }
+ case 8:
+ // Backspace
+
+ // This is a limited hack to enable overstrike effects.
+ // It backs the cursor up by one DisplayObject and then
continues
+ // the layout. E.g. you can use this to display an underline
+ // cursor inside a simulated text-entry box.
+ //
+ // ActionScript understands the '\b' escape sequence
+ // for inserting a BS DisplayObject.
+ //
+ // ONLY WORKS FOR BACKSPACING OVER ONE CHARACTER, WON'T BS
+ // OVER NEWLINES, ETC.
+
+ if (!rec.glyphs().empty())
+ {
+ // Peek at the previous glyph, and zero out its advance
+ // value, so the next char overwrites it.
+ float advance = rec.glyphs().back().advance;
+ x -= advance;
+ // Remove one glyph
+ rec.clearGlyphs(1);
+ }
+ continue;
+ case '<':
+ if (_html)
+ {
+ LOG_ONCE(log_debug(_("HTML in a text field is unsupported,
"
+ "gnash will just ignore the tags and "
+ "print their content")));
+
+ std::wstring discard;
+ bool complete = parseHTML(discard, it, e);
+
+ if (!complete) continue;
+ else break;
+
+ }
+ // If HTML isn't enabled, carry on and insert the glyph.
+
+ case 32:
+ last_space_glyph = rec.glyphs().size();
+ // Don't break, as we still need to insert the space glyph.
+
+ default:
+ {
+
+ // The font table holds up to 65535 glyphs. Casting
+ // from uint32_t would, in the event that the code
+ // is higher than 65535, result in the wrong DisplayObject
+ // being chosen. Flash can currently only handle 16-bit
+ // values.
+ int index = rec.getFont()->get_glyph_index(
+ static_cast<boost::uint16_t>(code), _embedFonts);
+
+ IF_VERBOSE_MALFORMED_SWF (
+ if (index == -1)
+ {
+ // Missing glyph! Log the first few errors.
+ static int s_log_count = 0;
+ if (s_log_count < 10)
+ {
+ s_log_count++;
+ if (_embedFonts)
+ {
+ log_swferror(_("TextField: missing embedded "
+ "glyph for char %d. Make sure
DisplayObject "
+ "shapes for font %s are being exported "
+ "into your SWF file"),
+ code, _font->name());
+ }
+ else
+ {
+ log_swferror(_("TextField: missing device "
+ "glyph for char %d. Maybe you don't have "
+ "font '%s' installed in your system."),
+ code, _font->name());
+ }
+ }
+
+ // Drop through and use index == -1; this will display
+ // using the empty-box glyph
+ }
+ );
+
+ SWF::TextRecord::GlyphEntry ge;
+ ge.index = index;
+ ge.advance = scale * rec.getFont()->get_advance(index,
+ _embedFonts);
+
+ rec.addGlyph(ge);
+
+ x += ge.advance;
+ }
+ }
+
+ float width = defBounds.width();
+ if (x >= width - rightMargin - PADDING_TWIPS)
+ {
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug("Text in TextField %s exceeds width [ _bounds %s ]",
+ getTarget(), _bounds);
+#endif
+
+ // No wrap and no resize: truncate
+ if (!doWordWrap() && autoSize == autoSizeNone)
+ {
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug(" wordWrap=false, autoSize=none");
+#endif
+ // Truncate long line, but keep expanding text box
+ bool newlinefound = false;
+ while (it != e)
+ {
+ code = *it++;
+ if (_embedFonts)
+ {
+ x += rec.getFont()->get_kerning_adjustment(last_code,
+ static_cast<int>(code)) * scale;
+ last_code = code;
+ }
+ // Expand the bounding-box to the lower-right corner
+ // of each glyph, even if we don't display it
+ m_text_bounding_box.expand_to_point(x, y + fontDescent);
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug("Text bbox expanded to %s (width: %f)",
+ m_text_bounding_box, m_text_bounding_box.width());
+#endif
+
+ if (code == 13 || code == 10)
+ {
+ newlinefound = true;
+ break;
+ }
+
+ int index = rec.getFont()->get_glyph_index(
+ static_cast<boost::uint16_t>(code), _embedFonts);
+ x += scale * rec.getFont()->get_advance(index,
_embedFonts);
+
+ }
+ if (!newlinefound) break;
+ }
+ else if ( doWordWrap() )
+ {
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug(" wordWrap=true");
+#endif
+
+ // Insert newline if there's space or autosize != none
+
+ // Close out this stretch of glyphs.
+ _textRecords.push_back(rec);
+
+ float previous_x = x;
+ x = leftMargin + blockIndent + PADDING_TWIPS;
+ y += fontHeight + leading;
+
+ // Start a new record on the next line.
+ rec.clearGlyphs();
+ rec.setXOffset(x);
+ rec.setYOffset(y);
+
+ // TODO : what if m_text_glyph_records is empty ?
+ // Is it possible ?
+ assert(!_textRecords.empty());
+ SWF::TextRecord& last_line = _textRecords.back();
+ if (last_space_glyph == -1)
+ {
+ // Pull the previous glyph down onto the
+ // new line.
+ if (!last_line.glyphs().empty())
+ {
+ rec.addGlyph(last_line.glyphs().back());
+ x += last_line.glyphs().back().advance;
+ previous_x -= last_line.glyphs().back().advance;
+ last_line.clearGlyphs(1);
+ }
+ }
+ else
+ {
+ // Move the previous word down onto the next line.
+
+ previous_x -= last_line.glyphs()[last_space_glyph].advance;
+
+ const SWF::TextRecord::Glyphs::size_type lineSize =
+ last_line.glyphs().size();
+ for (unsigned int i = last_space_glyph + 1; i < lineSize;
+ ++i)
+ {
+ rec.addGlyph(last_line.glyphs()[i]);
+ x += last_line.glyphs()[i].advance;
+ previous_x -= last_line.glyphs()[i].advance;
+ }
+ last_line.clearGlyphs(lineSize - last_space_glyph);
+ }
+
+ align_line(textAlignment, last_line_start_record, previous_x);
+
+ last_space_glyph = -1;
+ last_line_start_record = _textRecords.size();
+
+ }
+ else
+ {
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug(" wordWrap=%d, autoSize=%d", _wordWrap, _autoSize);
+#endif
+ }
+ }
+
+ if (y > (defBounds.height() - PADDING_TWIPS) &&
+ autoSize == autoSizeNone )
+ {
+#ifdef GNASH_DEBUG_TEXT_FORMATTING
+ log_debug("Text with wordWrap exceeds height of box");
+#endif
+ rec.clearGlyphs();
+ // TODO: should still compute m_text_bounds !
+ LOG_ONCE(log_unimpl("Computing text bounds of a TextField "
+ "containing text that doesn't fit the box
vertically"));
+ break;
+ }
+
+ if (m_cursor > idx)
+ {
+ m_xcursor = x;
+ m_ycursor = y;
+ }
+ idx++;
+
+ // TODO: HTML markup
+ }
+
+ // Expand bounding box to include the whole text (if autoSize)
+ if ( _autoSize != autoSizeNone )
+ {
+ _bounds.expand_to_point(x+PADDING_TWIPS, y+PADDING_TWIPS);
+ }
+
+ // Add this line to our output.
+ if (!rec.glyphs().empty()) _textRecords.push_back(rec);
+
+ float extra_space = align_line(textAlignment, last_line_start_record, x);
+
+ m_xcursor += static_cast<int>(extra_space);
+ m_ycursor -= fontHeight + (fontLeading - fontDescent);
+}
+
+TextField_as::VariableRef
+TextField_as::parseTextVariableRef(const std::string& variableName) const
+{
+ VariableRef ret;
+ ret.first = 0;
+
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("VariableName: %s"), variableName);
+#endif
+
+ /// Why isn't get_environment const again ?
+ as_environment& env = const_cast<TextField_as*>(this)->get_environment();
+
+ as_object* target = env.get_target();
+ if ( ! target )
+ {
+ IF_VERBOSE_MALFORMED_SWF(
+ log_swferror(_("Current environment has no target, "
+ "can't bind VariableName (%s) associated to "
+ "text field. Gnash will try to register "
+ "again on next access."), variableName);
+ );
+ return ret;
+ }
+
+ // If the variable string contains a path, we extract
+ // the appropriate target from it and update the variable
+ // name. We copy the string so we can assign to it if necessary.
+ std::string parsedName = variableName;
+ std::string path, var;
+ if (as_environment::parse_path(variableName, path, var))
+ {
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("Variable text Path: %s, Var: %s"), path, var);
+#endif
+ // find target for the path component
+ // we use our parent's environment for this
+ target = env.find_object(path);
+
+ parsedName = var;
+ }
+
+ if ( ! target )
+ {
+ IF_VERBOSE_MALFORMED_SWF(
+ log_swferror(_("VariableName associated to text field refers "
+ "to an unknown target (%s). It is possible that the "
+ "DisplayObject will be instantiated later in the SWF "
+ "stream. Gnash will try to register again on next "
+ "access."), path);
+ );
+ return ret;
+ }
+
+ ret.first = target;
+ ret.second = _vm.getStringTable().find(parsedName);
+
+ return ret;
+}
+
+void
+TextField_as::registerTextVariable()
+{
+//#define DEBUG_DYNTEXT_VARIABLES 1
+
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("registerTextVariable() called"));
+#endif
+
+ if ( _text_variable_registered )
+ {
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("registerTextVariable() no-op call (already registered)"));
+#endif
+ return;
+ }
+
+ if ( _variable_name.empty() )
+ {
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("string is empty, consider as registered"));
+#endif
+ _text_variable_registered=true;
+ return;
+ }
+
+ VariableRef varRef = parseTextVariableRef(_variable_name);
+ as_object* target = varRef.first;
+ if ( ! target )
+ {
+ log_debug(_("VariableName associated to text field (%s) refer to "
+ "an unknown target. It is possible that the DisplayObject "
+ "will be instantiated later in the SWF stream. "
+ "Gnash will try to register again on next access."),
+ _variable_name);
+ return;
+ }
+
+ string_table::key key = varRef.second;
+
+ // check if the VariableName already has a value,
+ // in that case update text value
+ as_value val;
+
+ int version = _vm.getSWFVersion();
+
+ if (target->get_member(key, &val) )
+ {
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("target object (%s @ %p) does have a member named %s"),
+ typeName(*target), (void*)target, _vm.getStringTable().value(key));
+#endif
+ // TODO: pass environment to to_string ?
+ // as_environment& env = get_environment();
+ setTextValue(utf8::decodeCanonicalString(val.to_string(), version));
+ }
+ else if ( _textDefined )
+ {
+ as_value newVal = as_value(utf8::encodeCanonicalString(_text,
version));
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("target sprite (%s @ %p) does NOT have a member "
+ "named %s (no problem, we'll add it with value %s)"),
+ typeName(*target), (void*)target,
+ _vm.getStringTable().value(key), newVal);
+#endif
+ target->set_member(key, newVal);
+ }
+ else
+ {
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug(_("target sprite (%s @ %p) does NOT have a member "
+ "named %s, and we don't have text defined"),
+ typeName(*target), (void*)target,
+ _vm.getStringTable().value(key));
+#endif
+ }
+
+ MovieClip* sprite = target->to_movie();
+
+ if ( sprite )
+ {
+ // add the textfield variable to the target sprite
+ // TODO: have set_textfield_variable take a string_table::key instead ?
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug("Calling set_textfield_variable(%s) against sprite %s",
+ _vm.getStringTable().value(key), sprite->getTarget());
+#endif
+ sprite->set_textfield_variable(_vm.getStringTable().value(key), this);
+
+ }
+ _text_variable_registered=true;
+
+}
+
+/// Parses an HTML tag (between < and >) and puts
+/// the contents into tag. Returns false if the
+/// tag was incomplete. The iterator is moved to after
+/// the closing tag or the end of the string.
+bool
+TextField_as::parseHTML(std::wstring& tag, std::wstring::const_iterator& it,
+ const std::wstring::const_iterator& e) const
+{
+
+ bool complete = false;
+
+ while (it != e)
+ {
+ if (*it == '>')
+ {
+ ++it;
+ complete = true;
+ break;
+ }
+
+ // Check for NULL DisplayObject
+ if (*it == 0) break;
+
+ tag.push_back(*it++);
+ }
+
+#ifdef GNASH_DEBUG_TEXTFIELDS
+ log_debug ("HTML tag: %s", utf8::encodeCanonicalString(tag, 7));
+#endif
+
+ return complete;
+}
+
+void
+TextField_as::set_variable_name(const std::string& newname)
+{
+ if ( newname != _variable_name )
+ {
+ _variable_name = newname;
+
+ // The name was empty or undefined, so there's nothing more to do.
+ if (_variable_name.empty()) return;
+
+ _text_variable_registered = false;
+
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug("Calling updateText after change of variable name");
+#endif
+
+ // Use the original definition text if this isn't dynamically
+ // created.
+ if (_tag) updateText(_tag->defaultText());
+
+#ifdef DEBUG_DYNTEXT_VARIABLES
+ log_debug("Calling registerTextVariable after change of variable "
+ "name and updateText call");
+#endif
+ registerTextVariable();
+ }
+}
+
+bool
+TextField_as::pointInShape(boost::int32_t x, boost::int32_t y) const
+{
+ SWFMatrix wm = getWorldMatrix();
+ point lp(x, y);
+ wm.invert().transform(lp);
+ return _bounds.point_test(lp.x, lp.y);
+}
+
+bool
+TextField_as::getDrawBorder() const
+{
+ return _drawBorder;
+}
+
+void
+TextField_as::setDrawBorder(bool val)
+{
+ if ( _drawBorder != val )
+ {
+ set_invalidated();
+ _drawBorder = val;
+ }
+}
+
+rgba
+TextField_as::getBorderColor() const
+{
+ return _borderColor;
+}
+
+void
+TextField_as::setBorderColor(const rgba& col)
+{
+ if ( _borderColor != col )
+ {
+ set_invalidated();
+ _borderColor = col;
+ }
+}
+
+bool
+TextField_as::getDrawBackground() const
+{
+ return _drawBackground;
+}
+
+void
+TextField_as::setDrawBackground(bool val)
+{
+ if ( _drawBackground != val )
+ {
+ set_invalidated();
+ _drawBackground = val;
+ }
+}
+
+rgba
+TextField_as::getBackgroundColor() const
+{
+ return _backgroundColor;
+}
+
+void
+TextField_as::setBackgroundColor(const rgba& col)
+{
+ if ( _backgroundColor != col )
+ {
+ set_invalidated();
+ _backgroundColor = col;
+ }
+}
+
+void
+TextField_as::setTextColor(const rgba& col)
+{
+ if (_textColor != col) {
+
+ set_invalidated();
+ _textColor = col;
+ std::for_each(_textRecords.begin(), _textRecords.end(),
+ boost::bind(&SWF::TextRecord::setColor, _1, _textColor));
+ }
+}
+
+void
+TextField_as::setEmbedFonts(bool use)
+{
+ if ( _embedFonts != use )
+ {
+ set_invalidated();
+ _embedFonts=use;
+ format_text();
+ }
+}
+
+void
+TextField_as::setWordWrap(bool on)
+{
+ if ( _wordWrap != on )
+ {
+ set_invalidated();
+ _wordWrap=on;
+ format_text();
+ }
+}
+
+cxform
+TextField_as::get_world_cxform() const
+{
+ // This is not automatically tested. See testsuite/samples/input-fields.swf
+ // for a manual check.
+
+ // If using a device font (PP compatibility), do not take parent cxform
+ // into account.
+ if (!getEmbedFonts()) return cxform();
+
+ return DisplayObject::get_world_cxform();
+}
+
+void
+TextField_as::setLeading(boost::uint16_t h)
+{
+ if ( _leading != h )
+ {
+ set_invalidated();
+ _leading = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setUnderlined(bool v)
+{
+ if ( _underlined != v )
+ {
+ set_invalidated();
+ _underlined = v;
+ format_text();
+ }
+}
+
+void
+TextField_as::setAlignment(TextAlignment h)
+{
+ if ( _alignment != h )
+ {
+ set_invalidated();
+ _alignment = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setIndent(boost::uint16_t h)
+{
+ if ( _indent != h )
+ {
+ set_invalidated();
+ _indent = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setBlockIndent(boost::uint16_t h)
+{
+ if ( _blockIndent != h )
+ {
+ set_invalidated();
+ _blockIndent = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setRightMargin(boost::uint16_t h)
+{
+ if ( _rightMargin != h )
+ {
+ set_invalidated();
+ _rightMargin = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setLeftMargin(boost::uint16_t h)
+{
+ if (_leftMargin != h)
+ {
+ set_invalidated();
+ _leftMargin = h;
+ format_text();
+ }
+}
+
+void
+TextField_as::setFontHeight(boost::uint16_t h)
+{
+ if ( _fontHeight != h )
+ {
+ set_invalidated();
+ _fontHeight = h;
+ format_text();
+ }
+}
+
+TextField_as::AutoSizeValue
+TextField_as::parseAutoSizeValue(const std::string& val)
+{
+ StringNoCaseEqual cmp;
+
+ if ( cmp(val, "left") )
+ {
+ return autoSizeLeft;
+ }
+ if ( cmp(val, "right") )
+ {
+ return autoSizeRight;
+ }
+ if ( cmp(val, "center") )
+ {
+ return autoSizeCenter;
+ }
+ return autoSizeNone;
+
+}
+
+const char*
+TextField_as::autoSizeValueName(AutoSizeValue val)
+{
+ switch (val)
+ {
+ case autoSizeLeft:
+ return "left";
+ case autoSizeRight:
+ return "right";
+ case autoSizeCenter:
+ return "center";
+ case autoSizeNone:
+ default:
+ return "none";
+ }
+
+}
+
+TextField_as::TypeValue
+TextField_as::parseTypeValue(const std::string& val)
+{
+ StringNoCaseEqual cmp;
+
+ if (cmp(val, "input")) return typeInput;
+ if (cmp(val, "dynamic")) return typeDynamic;
+ return typeInvalid;
+
+}
+
+const char*
+TextField_as::typeValueName(TypeValue val)
+{
+ switch (val)
+ {
+ case typeInput:
+ //log_debug("typeInput returned as 'input'");
+ return "input";
+ case typeDynamic:
+ //log_debug("typeDynamic returned as 'dynamic'");
+ return "dynamic";
+ default:
+ //log_debug("invalid type %d returned as 'invalid'", (int)val);
+ return "invalid";
+ }
+
+}
+
+void
+TextField_as::setAutoSize(AutoSizeValue val)
+{
+ if ( val == _autoSize ) return;
+
+ set_invalidated();
+
+ _autoSize = val;
+ format_text();
+}
+
+TextField_as::TextAlignment
+TextField_as::getTextAlignment()
+{
+ TextAlignment textAlignment = getAlignment();
+ if ( _autoSize == autoSizeCenter ) textAlignment = ALIGN_CENTER;
+ else if ( _autoSize == autoSizeLeft ) textAlignment = ALIGN_LEFT;
+ else if ( _autoSize == autoSizeRight ) textAlignment = ALIGN_RIGHT;
+ return textAlignment;
+}
+
+void
+TextField_as::onChanged()
+{
+ as_value met(PROPNAME("onChanged"));
+ as_value targetVal(this);
+ callMethod(NSV::PROP_BROADCAST_MESSAGE, met, targetVal);
+}
+
+/// This is called by movie_root when focus is applied to this TextField_as.
+//
+/// The return value is true if the TextField can recieve focus.
+bool
+TextField_as::handleFocus()
+{
+
+ set_invalidated();
+
+ /// Select the entire text on focus.
+ setSelection(0, _text.length());
+
+ m_has_focus = true;
+
+ // why should we add to the key listener list every time
+ // we call setFocus()???
+ _vm.getRoot().add_key_listener(this);
+
+ m_cursor = _text.size();
+ format_text();
+ return true;
+}
+
+/// This is called by movie_root when focus is removed from the
+/// current TextField.
+void
+TextField_as::killFocus()
+{
+ if ( ! m_has_focus ) return; // nothing to do
+
+ set_invalidated();
+ m_has_focus = false;
+
+ movie_root& root = _vm.getRoot();
+ root.remove_key_listener(this);
+ format_text(); // is this needed ?
+
+}
+
+void
+TextField_as::markReachableResources() const
+{
+
+ if (_tag) _tag->setReachable();
+
+ if (_font) _font->setReachable();
+
+ // recurse to parent...
+ markDisplayObjectReachable();
+}
+
+/// TextField interface functions
+
namespace {
void
+attachTextFieldStaticMembers(as_object& o)
+{
+ // Standard flags.
+ const int flags = as_prop_flags::dontDelete
+ |as_prop_flags::dontEnum;
+
+ // SWF6 or higher
+ const int swf6Flags = flags | as_prop_flags::onlySWF6Up;
+
+ o.init_member("getFontList",
+ new builtin_function(textfield_getFontList), swf6Flags);
+
+}
+
+void
+attachPrototypeProperties(as_object& o)
+{
+ // Standard flags.
+ const int flags = as_prop_flags::dontDelete
+ |as_prop_flags::dontEnum;
+
+ // SWF6 or higher
+ const int swf6Flags = flags | as_prop_flags::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);
+
+ getset = new builtin_function(textfield_variable);
+ o.init_property("variable", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_background);
+ o.init_property("background", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_text);
+ o.init_property("text", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_backgroundColor);
+ o.init_property("backgroundColor", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_border);
+ o.init_property("border", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_borderColor);
+ o.init_property("borderColor", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_textColor);
+ o.init_property("textColor", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_embedFonts);
+ o.init_property("embedFonts", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_autoSize);
+ o.init_property("autoSize", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_type);
+ o.init_property("type", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_wordWrap);
+ o.init_property("wordWrap", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_html);
+ o.init_property("html", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_selectable);
+ o.init_property("selectable", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_length);
+ o.init_property("length", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_maxscroll);
+ o.init_property("maxscroll", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_maxhscroll);
+ o.init_property("maxhscroll", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_maxChars);
+ o.init_property("maxChars", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_bottomScroll);
+ o.init_property("bottomScroll", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_scroll);
+ o.init_property("scroll", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_hscroll);
+ o.init_property("hscroll", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_restrict);
+ o.init_property("restrict", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_multiline);
+ o.init_property("multiline", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_password);
+ o.init_property("password", *getset, *getset, swf6Flags);
+ getset = new builtin_function(textfield_htmlText);
+ o.init_property("htmlText", *getset, *getset, swf6Flags);
+}
+
+
+as_value
+textfield_background(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ if (fn.nargs == 0) {
+ return as_value(ptr->getBackgroundColor().toRGB());
+ }
+ else {
+ rgba newColor;
+ newColor.parseRGB(static_cast<boost::uint32_t>(fn.arg(0).to_int()));
+ ptr->setBackgroundColor(newColor);
+ }
+
+ return as_value();
+}
+
+as_value
+textfield_borderColor(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ if ( fn.nargs == 0 ) // getter
+ {
+ return ptr->autoSizeValueName(ptr->getAutoSize());
+ }
+ else // setter
+ {
+ const as_value& arg = fn.arg(0);
+ if ( arg.is_bool() )
+ {
+ if ( arg.to_bool() ) // true == left
+ {
+ ptr->setAutoSize( TextField_as::autoSizeLeft );
+ }
+ else
+ {
+ ptr->setAutoSize( TextField_as::autoSizeNone );
+ }
+ }
+ else
+ {
+ std::string strval = arg.to_string();
+ TextField_as::AutoSizeValue val = ptr->parseAutoSizeValue(strval);
+ ptr->setAutoSize( val );
+ }
+ }
+
+ return as_value();
+}
+
+as_value
+textfield_type(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+
+ if (!fn.nargs)
+ {
+ // getter
+ return ptr->typeValueName(ptr->getType());
+ }
+
+ // setter
+ const as_value& arg = fn.arg(0);
+ std::string strval = arg.to_string();
+ TextField_as::TypeValue val = ptr->parseTypeValue(strval);
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( val == TextField_as::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)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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)
+{
+ // TODO: make this a DisplayObject::getDepth_method function...
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ int n = text->get_depth();
+
+ return as_value(n);
+
+}
+
+as_value
+textfield_getFontList(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE(log_unimpl("TextField.getFontList()"));
+
+ return as_value();
+}
+
+as_value
+textfield_getNewTextFormat(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE(log_unimpl("TextField.getNewTextFormat()"));
+
+ return as_value();
+}
+
+as_value
+textfield_setNewTextFormat(const fn_call& fn)
+{
+ //boost::intrusive_ptr<TextField> text =
ensureType<TextField>(fn.this_ptr);
+ //UNUSED(text);
+
+ LOG_ONCE( log_unimpl("TextField.setNewTextFormat(), we'll delegate "
+ "to setTextFormat") );
+ return textfield_setTextFormat(fn);
+
+ //return as_value();
+}
+
+as_value
+textfield_password(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ LOG_ONCE(log_unimpl("TextField.password"));
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ LOG_ONCE(log_unimpl("TextField.multiline"));
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.restrict"));
+
+ return as_value();
+}
+
+as_value
+textfield_bottomScroll(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.bottomScroll"));
+
+ return as_value();
+}
+
+as_value
+textfield_bottomScrollV(const fn_call& fn)
+{
+//TODO: AS3 Method
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.bottomScroll"));
+
+ return as_value();
+}
+
+as_value
+textfield_maxhscroll(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.maxhscroll"));
+
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ LOG_ONCE(log_unimpl("TextField.maxChars"));
+
+ 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(fn.arg(0).to_int());
+ return as_value();
+}
+
+as_value
+textfield_text(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+ if (!fn.nargs)
+ {
+ // Getter
+ //
+ // FIXME: should return text without HTML tags.
+ return as_value(ptr->get_text_value());
+ }
+
+ // Setter
+ int version = ptr->getVM().getSWFVersion();
+ ptr->setTextValue(
+ utf8::decodeCanonicalString(fn.arg(0).to_string(), version));
+
+ return as_value();
+}
+
+as_value
+textfield_htmlText(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> ptr =
ensureType<TextField_as>(fn.this_ptr);
+ if (!fn.nargs)
+ {
+ // Getter
+ return as_value(ptr->get_text_value());
+ }
+
+ // Setter
+ int version = ptr->getVM().getSWFVersion();
+ ptr->setTextValue(
+ 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)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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 = text->getVM().getSWFVersion();
+ if (version < 8 && replace.empty()) return as_value();
+
+ text->replaceSelection(replace);
+
+ return as_value();
+}
+
+as_value
+textfield_scroll(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.scroll()"));
+
+ return as_value();
+}
+
+as_value
+textfield_hscroll(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.hscroll()"));
+
+ return as_value();
+}
+
+as_value
+textfield_maxscroll(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE (log_unimpl("TextField.maxscroll"));
+
+ return as_value();
+}
+
+as_value
+textfield_getCharBoundaries(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_antiAliasType(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_sharpness(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_gridFitType(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_condenseWhite(const fn_call& fn)
+{
+//TODO:
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getCharIndexAtPoint(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getFirstCharInParagraph(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getImageReference(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineIndexAtPoint(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineIndexOfChar(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineLength(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineMetrics(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineOffset(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getLineText(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_mouseWheelEnabled(const fn_call& fn)
+{
+//TODO:
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_styleSheet(const fn_call& fn)
+{
+//TODO:
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getParagraphLength(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_getTextFormat(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ boost::intrusive_ptr<TextFormat_as> tf = new TextFormat_as;
+ 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->italicedSet(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(tf.get());
+}
+
+as_value
+textfield_replaceSelectedText(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_replaceText(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+ UNUSED(text);
+
+ LOG_ONCE(log_unimpl("TextField.replaceText()"));
+
+ return as_value();
+}
+
+as_value
+textfield_removeTextField(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ text->removeTextField();
+
+ LOG_ONCE(log_debug("TextField.removeTextField() TESTING"));
+
+ return as_value();
+}
+
+as_value
+textfield_setSelection(const fn_call& fn)
+{
+//TODO: AS3 method
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_setTextFormat(const fn_call& fn)
+{
+ boost::intrusive_ptr<TextField_as> text =
ensureType<TextField_as>(fn.this_ptr);
+
+ 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());
+ }
+
+ as_object* obj = fn.arg(0).to_object().get();
+ if ( ! obj )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::stringstream ss; fn.dump_args(ss);
+ log_aserror("TextField.setTextFormat(%s) : %s", ss.str(),
+ _("first argument is not an object"))
+ );
+ return as_value();
+ }
+
+ TextFormat_as* tf = dynamic_cast<TextFormat_as*>(obj);
+ if ( ! 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 ( tf->alignDefined() ) text->setAlignment(tf->align());
+ if ( tf->sizeDefined() ) text->setFontHeight(tf->size()); // keep twips
+ if ( tf->indentDefined() ) text->setIndent(tf->indent());
+ if ( tf->blockIndentDefined() ) text->setBlockIndent(tf->blockIndent());
+ if ( tf->leadingDefined() ) text->setLeading(tf->leading());
+ if ( tf->leftMarginDefined() ) text->setLeftMargin(tf->leftMargin());
+ if ( tf->rightMarginDefined() ) text->setRightMargin(tf->rightMargin());
+ if ( tf->colorDefined() ) text->setTextColor(tf->color());
+ if ( tf->underlinedDefined() ) text->setUnderlined(tf->underlined());
+
+ if ( tf->fontDefined() )
+ {
+ const std::string& fontName = tf->font();
+ if ( ! fontName.empty() )
+ {
+ bool bold = tf->bold();
+ bool italic = tf->italiced();
+
+ // 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
+
+ LOG_ONCE( log_unimpl("TextField.setTextFormat() discards url, target, "
+ "tabStops, bullet and display") );
+
+ return as_value();
+}
+
+as_value
+textfield_change(const fn_call& fn)
+{
+//FIXME: This is an AS3 event.
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_link(const fn_call& fn)
+{
+//FIXME: This is an AS3 event
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_textInput(const fn_call& fn)
+{
+//FIXME: This is an AS3 event
+// boost::intrusive_ptr<TextField_as> ptr =
+// ensureType<TextField_as>(fn.this_ptr);
+// UNUSED(ptr);
+// log_unimpl (__FUNCTION__);
+ return as_value();
+}
+
+as_value
+textfield_ctor(const fn_call& fn)
+{
+ VM& vm = fn.getVM();
+
+ as_object* proto = getTextFieldInterface(vm);
+
+ as_object* obj = 0;
+
+ if ( vm.getSWFVersion() < 9 )
+ {
+ // We should attach more properties to the prototype on first
+ // instantiation.
+ // TODO: this also attaches properties to the SWF5 prototype but makes
+ // them invisible with prop flags. Is this correct?
+ attachPrototypeProperties(*proto);
+
+ obj = new as_object(proto);
+ }
+ else
+ {
+ rect nullRect;
+ obj = new TextField_as(0, nullRect);
+ }
+
+ return as_value(obj);
+}
+
+void
attachTextFieldInterface(as_object& o)
{
o.init_member("getCharBoundaries", new
builtin_function(textfield_getCharBoundaries));
@@ -118,222 +3003,26 @@
}
as_object*
-getTextFieldInterface()
+getTextFieldInterface(VM& vm)
{
- static boost::intrusive_ptr<as_object> o;
- if ( ! o ) {
- o = new as_object();
- attachTextFieldInterface(*o);
+ static boost::intrusive_ptr<as_object> proto;
+
+ if ( proto == NULL )
+ {
+ if (vm.getSWFVersion() < 6) {
+ /// The prototype for SWF5 is a simple as_object without
+ /// toString() or valueOf().
+ proto = new as_object();
+ vm.addStatic(proto.get());
+ }
+ else {
+ proto = new as_object(getObjectInterface());
+ vm.addStatic(proto.get());
+ attachTextFieldInterface(*proto);
+ }
+
}
- return o.get();
-}
-
-as_value
-textfield_getCharBoundaries(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getCharIndexAtPoint(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getFirstCharInParagraph(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getImageReference(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineIndexAtPoint(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineIndexOfChar(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineLength(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineMetrics(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineOffset(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getLineText(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getParagraphLength(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_getTextFormat(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_replaceSelectedText(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_replaceText(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_setSelection(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_setTextFormat(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_change(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_link(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_scroll(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_textInput(const fn_call& fn)
-{
- boost::intrusive_ptr<TextField_as> ptr =
- ensureType<TextField_as>(fn.this_ptr);
- UNUSED(ptr);
- log_unimpl (__FUNCTION__);
- return as_value();
-}
-
-as_value
-textfield_ctor(const fn_call& fn)
-{
- boost::intrusive_ptr<as_object> obj = new TextField_as;
-
- return as_value(obj.get()); // will keep alive
+ return proto.get();
}
} // anonymous namespace
=== modified file 'libcore/asobj/flash/text/TextField_as.h'
--- a/libcore/asobj/flash/text/TextField_as.h 2009-05-28 17:29:17 +0000
+++ b/libcore/asobj/flash/text/TextField_as.h 2009-06-08 22:24:55 +0000
@@ -22,16 +22,647 @@
#ifdef HAVE_CONFIG_H
#include "gnashconfig.h"
+#include "InteractiveObject.h" // for inheritance
+#include "styles.h" // for line_style
+#include "fill_style.h"
+#include "Range2d.h"
+#include "rect.h" // for inlines
+#include "Font.h" // for visibility of font add_ref/drop_ref
#endif
namespace gnash {
+ namespace SWF {
+ class DefineEditTextTag;
+ class TextRecord;
+ }
// Forward declarations
-class as_object;
-
-/// Initialize the global TextField class
-void textfield_class_init(as_object& global);
+class TextField_as : public InteractiveObject
+{
+
+public:
+
+ /// Text alignment values
+ enum TextAlignment
+ {
+ ALIGN_LEFT = 0,
+ ALIGN_RIGHT,
+ ALIGN_CENTER,
+ ALIGN_JUSTIFY
+ };
+
+ /// Possible autoSize values
+ enum AutoSizeValue {
+
+ /// Do not automatically resize TextField as text grow/shrink
+ autoSizeNone,
+
+ /// Expand TextField, anchor the top-left side
+ autoSizeLeft,
+
+ /// Expand TextField, anchor the horizontal center
+ autoSizeCenter,
+
+ /// Expand TextField, anchor the top-right side
+ autoSizeRight
+ };
+
+ /// Possible type values
+ enum TypeValue {
+
+ /// Invalid value
+ typeInvalid,
+
+ /// Do not accept input, text is only changed by variable name
+ /// or assigning to the .text member
+ typeDynamic,
+
+ /// Accept user input
+ typeInput
+ };
+
+ /// Constructs a TextField as specified in a DefineEditText tag.
+ TextField_as(DisplayObject* parent, const SWF::DefineEditTextTag& def,
int id);
+
+ /// Constructs a TextField with default values and the specified bounds.
+ //
+ /// Notably, the default textHeight is 12pt (240 twips).
+ TextField_as(DisplayObject* parent, const rect& bounds);
+
+ ~TextField_as();
+
+ // TODO: should this return isSelectable() ?
+ bool mouseEnabled() const { return true; }
+
+ InteractiveObject* topmostMouseEntity(boost::int32_t x,
+ boost::int32_t y);
+
+ // Text fields need to handle cxform specially
+ virtual cxform get_world_cxform() const;
+
+ bool wantsInstanceName() const
+ {
+ return true; // text fields can be referenced
+ }
+
+ bool on_event(const event_id& id);
+
+ const std::string& getVariableName() const
+ {
+ return _variable_name;
+ }
+
+ /// Set the name of a variable associated to this
+ /// TextField's displayed text.
+ //
+ /// Calling this function will override any previous
+ /// setting for the variable name.
+ ///
+ void set_variable_name(const std::string& newname);
+
+ /// \brief Set our text to the given string by effect of an update of a
+ /// registered variable name
+ //
+ /// This call only updates the text and is only meant to be called
+ /// by ourselves or by MovieClip when a registered TextVariable is
+ /// updated.
+ void updateText(const std::string& s);
+
+ /// Return value of our text.
+ std::string get_text_value() const;
+
+ /// Return true if text is defined
+ bool getTextDefined() const { return _textDefined; }
+
+ size_t getCaretIndex() const {
+ return m_cursor;
+ }
+
+ const std::pair<size_t, size_t>& getSelection() const {
+ return _selection;
+ }
+
+ /// Replace the current selection with the new text.
+ void replaceSelection(const std::string& replace);
+
+ /// Set the current selection
+ //
+ /// @param start The index of the beginning of the selection.
+ /// @param end The index of the end of the selection.
+ //
+ /// If start is greater than end, the values are swapped, ensuring
+ /// end is never less than start.
+ void setSelection(int start, int end);
+
+ /// We have a "text" member.
+ bool set_member(string_table::key name, const as_value& val,
+ string_table::key nsname = 0, bool ifFound=false);
+
+ bool get_member(string_table::key name, as_value* val,
+ string_table::key nsname = 0);
+
+ /// Draw the dynamic string.
+ void display();
+
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
+
+ virtual rect getBounds() const
+ {
+ return _bounds;
+ }
+
+ // See dox in DisplayObject.h
+ bool pointInShape(boost::int32_t x, boost::int32_t y) const;
+
+ /// Return true if the 'background' should be drawn
+ bool getDrawBackground() const;
+
+ /// Specify wheter to draw the background
+ void setDrawBackground(bool draw);
+
+ /// Return color of the background
+ rgba getBackgroundColor() const;
+
+ /// Set color of the background
+ //
+ /// Use setDrawBackground to actually use this value.
+ ///
+ void setBackgroundColor(const rgba& col);
+
+ /// Return true if this TextField should have it's border visible
+ bool getDrawBorder() const;
+
+ /// Specify wheter to draw the border
+ void setDrawBorder(bool draw);
+
+ /// Return color of the border
+ rgba getBorderColor() const;
+
+ /// Set color of the border
+ //
+ /// Use setDrawBorder to actually use this value.
+ ///
+ void setBorderColor(const rgba& col);
+
+ /// Return color of the text
+ const rgba& getTextColor() const
+ {
+ return _textColor;
+ }
+
+ /// Set color of the text
+ void setTextColor(const rgba& col);
+
+ /// \brief
+ /// Return true if this TextField should use embedded font glyphs,
+ /// false if it should use device font glyphs
+ bool getEmbedFonts() const {
+ return _embedFonts;
+ }
+
+ /// Get the current maxChars setting of the TextField
+ boost::int32_t maxChars() const {
+ return _maxChars;
+ }
+
+ /// Set the current maxChars setting of the TextField
+ void maxChars(boost::int32_t max) {
+ _maxChars = max;
+ }
+
+ /// Get the current multiline setting of the TextField
+ bool multiline() const {
+ return _multiline;
+ }
+
+ /// Set the current multiline setting of the TextField
+ void multiline(bool b) {
+ _multiline = b;
+ }
+
+ /// Get the current password setting of the TextField
+ bool password() const {
+ return _password;
+ }
+
+ /// Set the current password setting of the TextField
+ void password(bool b) {
+ _password = b;
+ }
+ /// \brief
+ /// Set whether this TextField should use embedded font glyphs,
+ /// or use device font glyphs
+ //
+ /// @param use
+ void setEmbedFonts(bool use);
+
+ /// Get autoSize value
+ AutoSizeValue getAutoSize() const
+ {
+ return _autoSize;
+ }
+
+ /// Return text TextAlignment
+ TextAlignment getTextAlignment();
+
+ /// Set autoSize value
+ //
+ /// @param val
+ /// The AutoSizeValue to use
+ ///
+ void setAutoSize(AutoSizeValue val);
+
+ /// Parse autoSize string value
+ //
+ /// @param val
+ /// Auto size value as a string (one of none, left, center, right)
+ ///
+ /// @return an AutoSizeValue identifier. autoSizeNone if invalid
+ ///
+ static AutoSizeValue parseAutoSizeValue(const std::string& val);
+
+ /// Return autoSize value as a string
+ //
+ /// @param val
+ /// Auto size value
+ ///
+ /// @return a C-string representation of the autoSize value.
+ /// The returns is *never* NULL.
+ ///
+ static const char* autoSizeValueName(AutoSizeValue val);
+
+ /// Set type (input or dynamic)
+ //
+ /// @param val
+ /// The TypeValue to use, no-op if typeInvalid.
+ ///
+ void setType(TypeValue val) { if (val != typeInvalid) _type=val; }
+
+ /// Get type (input, dynamic or invalid)
+ TypeValue getType() const
+ {
+ return _type;
+ }
+
+ /// Return true if this TextField is read-only
+ bool isReadOnly() const { return _type != typeInput; }
+
+ /// Parse type string value
+ //
+ /// @param val
+ /// Type value as a string (one of input or dynamic)
+ ///
+ /// @return an TypeValue identifier. typeInvalid if invalid.
+ ///
+ static TypeValue parseTypeValue(const std::string& val);
+
+ /// Return type value as a string
+ //
+ /// @param val
+ /// Type value (enum)
+ ///
+ /// @return a C-string representation of the type value.
+ /// The returns is *never* NULL.
+ ///
+ static const char* typeValueName(TypeValue val);
+
+ /// \brief
+ /// Return true if text should continue to next available line
+ /// when hitting end of bounding box.
+ ///
+ bool doWordWrap() const {
+ return _wordWrap;
+ }
+
+ /// Set wordWrap parameter
+ //
+ /// @param on
+ /// If true text hitting bounding box limits will continue
+ /// to next line.
+ /// If false, either text will be truncated or bounding box
+ /// expanded, depending on autoSize (see getAutoSize)
+ ///
+ void setWordWrap(bool on);
+
+ /// \brief
+ /// Return true if HTML markup in text should be rendered.
+ ///
+ bool doHtml() const {
+ return _html;
+ }
+
+ /// Set html parameter
+ //
+ /// @param on
+ /// If true HTML tags in the text will be parsed and rendered
+ void setHtml(bool on) {
+ _html = on;
+ }
+
+ /// Return true if the TextField text is selectable
+ bool isSelectable() const
+ {
+ return _selectable;
+ }
+
+ /// Set 'selectable' parameter
+ void setSelectable(bool v)
+ {
+ _selectable = v;
+ }
+
+ // See DisplayObject::isActiveTextField
+ virtual bool isSelectableTextField() const
+ {
+ return isSelectable();
+ }
+
+ /// Remove this textfield from the stage
+ //
+ /// This is to implement TextField.removeTextField, will
+ /// basically forward the request to its parent.
+ /// Eventually this and MovieClip::removeMovieClip
+ /// will be merged in a single function to be later used
+ /// also for AS3 removeChild().
+ ///
+ void removeTextField();
+
+ /// Set our font, return previously set one.
+ //
+ /// @param newfont
+ /// Will be stored in an intrusive_ptr
+ ///
+ boost::intrusive_ptr<const Font> setFont(
+ boost::intrusive_ptr<const Font> newfont);
+
+ const Font* getFont() { return _font.get(); }
+
+ boost::uint16_t getFontHeight() const
+ {
+ return _fontHeight;
+ }
+
+ void setFontHeight(boost::uint16_t h);
+
+ boost::uint16_t getLeftMargin() const
+ {
+ return _leftMargin;
+ }
+
+ void setLeftMargin(boost::uint16_t h);
+
+ boost::uint16_t getRightMargin() const
+ {
+ return _rightMargin;
+ }
+
+ void setRightMargin(boost::uint16_t h);
+
+ boost::uint16_t getIndent() const
+ {
+ return _indent;
+ }
+
+ void setIndent(boost::uint16_t h);
+
+ boost::uint16_t getBlockIndent() const
+ {
+ return _blockIndent;
+ }
+
+ void setBlockIndent(boost::uint16_t h);
+
+ TextAlignment getAlignment() const
+ {
+ return _alignment;
+ }
+
+ void setAlignment(TextAlignment h);
+
+ boost::uint16_t getLeading() const
+ {
+ return _leading;
+ }
+
+ void setLeading(boost::uint16_t h);
+
+ bool getUnderlined() const
+ {
+ return _underlined;
+ }
+
+ void setUnderlined(bool v);
+
+ const rect& getTextBoundingBox() const
+ {
+ return m_text_bounding_box;
+ }
+
+ /// Set our text to the given string.
+ //
+ /// This function will also update any registered variable
+ ///
+ void setTextValue(const std::wstring& wstr);
+
+ static void init(as_object& global);
+
+protected:
+
+ /// Mark reachable reosurces (for GC)
+ //
+ /// Reachable resources are:
+ /// - The font being used (m_font)
+ /// - Our definition
+ /// - Common DisplayObject resources
+ ///
+ void markReachableResources() const;
+
+private:
+
+ /// \brief Set our text to the given string by effect of an update of a
+ /// registered variable name
+ //
+ /// This call only updates the text and is only meant to be called
+ /// by ourselves or by MovieClip when a registered TextVariable is
+ /// updated.
+ void updateText(const std::wstring& s);
+
+ void insertTab(SWF::TextRecord& rec, boost::int32_t& x, float scale);
+
+ /// What happens when setFocus() is called on this TextField.
+ //
+ /// @return true if focus was set. A TextField can always receive focus,
+ /// so this always returns true.
+ virtual bool handleFocus();
+
+ /// Kill focus
+ virtual void killFocus();
+
+ /// Call this function when willing to invoke the onChanged event
handler
+ void onChanged();
+
+ /// Reset our text bounding box to the given point.
+ void reset_bounding_box(boost::int32_t x, boost::int32_t y)
+ {
+ m_text_bounding_box.set_to_point(x, y);
+ }
+
+ /// Convert the DisplayObjects in _text into a series of
+ /// text_glyph_records to be rendered.
+ void format_text();
+
+ /// Extracts an HTML tag.
+ ///
+ /// @param tag This string is filled with the extracted HTML tag.
+ /// @param it An iterator pointing to the first DisplayObject of the
+ /// HTML tag. It is left pointing to the DisplayObject
after the
+ /// closing tag or the end of the string.
+ /// @param e An iterator pointing to the end of the string.
+ /// @return Whether the tag is complete or not (i.e. whether a '>'
+ /// was found).
+ bool parseHTML(std::wstring& tag, std::wstring::const_iterator& it,
+ const std::wstring::const_iterator& e) const;
+
+ /// Does LEFT/CENTER/RIGHT alignment on the records in
+ /// m_text_glyph_records[], starting with
+ /// last_line_start_record and going through the end of
+ /// m_text_glyph_records.
+ float align_line(TextAlignment align, int last_line_start_record, float
x);
+
+ /// Associate a variable to the text of this DisplayObject
+ //
+ /// Setting the associated variable actually changes the
+ /// displayed text. Getting the variable would return the
+ /// displayed text.
+ ///
+ /// If the given variable already exist use it to set
+ /// current text before overriding it.
+ ///
+ /// Since the variable target may be undefined at time
+ /// of instantiation of this EditText DisplayObject, the
+ /// class keeps track of wheter it succeeded registering
+ /// the variable and this function will do nothing in this
+ /// case. Thus it is safe to call it multiple time, using
+ /// an as-needed policy (will be called from get_text_value and
+ /// display)
+ ///
+ void registerTextVariable();
+
+ typedef std::pair<as_object*, string_table::key> VariableRef;
+
+ /// \brief
+ /// Parse the given variable name
+ /// into sprite and a string_table::key components
+ ///
+ VariableRef parseTextVariableRef(const std::string& variableName) const;
+
+ /// The immutable definition of our TextField
+ //
+ /// This is NULL for dynamic TextFields.
+ boost::intrusive_ptr<const SWF::DefineEditTextTag> _tag;
+
+ /// The actual text.
+ //
+ /// Because we have to deal with non-ascii DisplayObjects (129-255), this
+ /// is a wide string; the cursor position and the position within the
+ /// string are then the same, which makes manipulating the string much
+ /// easier.
+ std::wstring _text;
+
+ /// This flag will be true as soon as the TextField
+ /// is assigned a text value. Only way to be false is
+ /// when definition has the hasText flag set to false
+ /// and no actionscript added text.
+ bool _textDefined;
+
+ /// bounds of dynamic text, as laid out
+ rect m_text_bounding_box;
+
+ typedef std::vector<SWF::TextRecord> TextRecords;
+ TextRecords _textRecords;
+ bool _underlined;
+
+ boost::uint16_t _leading;
+
+ TextAlignment _alignment;
+
+ boost::uint16_t _indent;
+
+ /// Indentation for every line (including the ones created by
+ /// effect of a word-wrap.
+ boost::uint16_t _blockIndent;
+
+ boost::uint16_t _leftMargin;
+
+ boost::uint16_t _rightMargin;
+
+ boost::uint16_t _fontHeight;
+
+ boost::intrusive_ptr<const Font> _font;
+
+ bool m_has_focus;
+ size_t m_cursor;
+ void show_cursor(const SWFMatrix& mat);
+ float m_xcursor;
+ float m_ycursor;
+
+ /// Corresponds to the multiline property.
+ bool _multiline;
+
+ /// Corresponds to the password property.
+ bool _password;
+
+ /// Corresponds to the maxChars property.
+ boost::int32_t _maxChars;
+ /// The flag keeping status of TextVariable registration
+ //
+ /// It will be set to true if there's no need to register
+ /// a text variable (ie. non-specified in the SWF)
+ ///
+ bool _text_variable_registered;
+
+ /// The text variable name
+ //
+ /// This is stored here, and not just in the definition,
+ /// because it can be changed programmatically, by setting
+ /// 'TextFields.variable'
+ std::string _variable_name;
+
+ bool _drawBackground;
+
+ rgba _backgroundColor;
+
+ bool _drawBorder;
+
+ rgba _borderColor;
+
+ rgba _textColor;
+
+ bool _embedFonts;
+
+ bool _wordWrap;
+
+ bool _html;
+
+ bool _selectable;
+
+ AutoSizeValue _autoSize;
+
+ TypeValue _type;
+
+ /// Area in which the text is drawn.
+ //
+ /// This area encloses all the text, can be automatically
+ /// extended to fit text or hide text overflowing it.
+ /// See the setAutoSize() method to change that.
+ ///
+ rect _bounds;
+
+ /// Represents the selected part of the text. The second element must
+ /// never be less than the first.
+ std::pair<size_t, size_t> _selection;
+};
} // gnash namespace
=== modified file 'libcore/asobj/flash/text/TextFormat_as.cpp'
--- a/libcore/asobj/flash/text/TextFormat_as.cpp 2009-06-08 18:31:05
+0000
+++ b/libcore/asobj/flash/text/TextFormat_as.cpp 2009-06-08 22:24:55
+0000
@@ -27,7 +27,7 @@
#include "smart_ptr.h" // for boost intrusive_ptr
#include "builtin_function.h" // need builtin_function
#include "GnashException.h" // for ActionException
-#include "TextField.h"
+#include "text/TextField_as.h"
#include "VM.h"
#include "RGBA.h" // for rgba type
#include "namedStrings.h"
@@ -41,8 +41,8 @@
void attachTextFormatInterface(as_object& o);
void attachTextFormatStaticInterface(as_object& o);
as_object* getTextFormatInterface();
- const char* getAlignString(TextField::TextAlignment a);
- TextField::TextAlignment parseAlignString(const std::string& align);
+ const char* getAlignString(TextField_as::TextAlignment a);
+ TextField_as::TextAlignment parseAlignString(const std::string& align);
as_value textformat_display(const fn_call& fn);
as_value textformat_bullet(const fn_call& fn);
@@ -135,7 +135,7 @@
_bold(false),
_italic(false),
_bullet(false),
- _align(TextField::ALIGN_LEFT),
+ _align(TextField_as::ALIGN_LEFT),
_blockIndent(-1),
_color(),
_indent(-1),
@@ -520,31 +520,31 @@
return as_value();
}
-TextField::TextAlignment
+TextField_as::TextAlignment
parseAlignString(const std::string& align)
{
StringNoCaseEqual cmp;
- if ( cmp(align, "left") ) return TextField::ALIGN_LEFT;
- if ( cmp(align, "center") ) return TextField::ALIGN_CENTER;
- if ( cmp(align, "right") ) return TextField::ALIGN_RIGHT;
- if ( cmp(align, "justify") ) return TextField::ALIGN_JUSTIFY;
+ if ( cmp(align, "left") ) return TextField_as::ALIGN_LEFT;
+ if ( cmp(align, "center") ) return TextField_as::ALIGN_CENTER;
+ if ( cmp(align, "right") ) return TextField_as::ALIGN_RIGHT;
+ if ( cmp(align, "justify") ) return TextField_as::ALIGN_JUSTIFY;
log_debug("Invalid align string %s, taking as left", align);
- return TextField::ALIGN_LEFT;
+ return TextField_as::ALIGN_LEFT;
}
const char*
-getAlignString(TextField::TextAlignment a)
+getAlignString(TextField_as::TextAlignment a)
{
switch (a)
{
- case TextField::ALIGN_LEFT:
+ case TextField_as::ALIGN_LEFT:
return "left";
- case TextField::ALIGN_CENTER:
+ case TextField_as::ALIGN_CENTER:
return "center";
- case TextField::ALIGN_RIGHT:
+ case TextField_as::ALIGN_RIGHT:
return "right";
- case TextField::ALIGN_JUSTIFY:
+ case TextField_as::ALIGN_JUSTIFY:
return "justify";
default:
log_error("Uknown alignment value: %d, take as left",
a);
=== modified file 'libcore/asobj/flash/text/TextFormat_as.h'
--- a/libcore/asobj/flash/text/TextFormat_as.h 2009-06-08 18:31:05 +0000
+++ b/libcore/asobj/flash/text/TextFormat_as.h 2009-06-08 22:24:55 +0000
@@ -23,7 +23,7 @@
#ifdef HAVE_CONFIG_H
#include "as_object.h" // for inheritance of TextFormat
#include "gnashconfig.h"
-#include "TextField.h" // for TextAlignment enum
+#include "text/TextField_as.h" // for TextAlignment enum
#include "RGBA.h" // for rgba
#include <boost/cstdint.hpp> // for boost::uint32_t
#include <string>
@@ -72,7 +72,7 @@
bool indentDefined() const { return _flags&DEFindent; }
/// Return the alignment of the paragraph.
- TextField::TextAlignment align() const { return _align; }
+ TextField_as::TextAlignment align() const { return _align; }
bool alignDefined() const { return _flags&DEFalign; }
/// Return the name of a font for text as a string.
@@ -122,7 +122,7 @@
void indentSet(boost::uint16_t x) { _indent = x; _flags |=
DEFindent; }
void fontSet(const std::string& font) { _font=font; _flags |= DEFfont; }
- void alignSet(TextField::TextAlignment x) {
+ void alignSet(TextField_as::TextAlignment x) {
_align = x;
_flags |= DEFalign;
}
@@ -198,7 +198,7 @@
/// paragraph is centered. If "right", the paragraph is
/// right-aligned. If "justify", the paragraph is justified.
///
- TextField::TextAlignment _align;
+ TextField_as::TextAlignment _align;
//
boost::uint16_t _blockIndent;
=== modified file 'libcore/asobj/flash/text/text.am'
--- a/libcore/asobj/flash/text/text.am 2009-06-08 18:31:05 +0000
+++ b/libcore/asobj/flash/text/text.am 2009-06-08 22:24:55 +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 2009-04-15 09:08:37 +0000
+++ b/libcore/swf/DefineEditTextTag.cpp 2009-06-08 22:24:55 +0000
@@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "DefineEditTextTag.h"
-#include "TextField.h"
+#include "text/TextField_as.h"
#include "movie_definition.h"
#include "Font.h"
#include "SWFStream.h"
@@ -43,7 +43,7 @@
{
// Resolve the font, if possible
getFont();
- TextField* ch = new TextField(parent, *this, id);
+ TextField_as* ch = new TextField_as(parent, *this, id);
// This gives an "instance name" to the TextField, but
// it is not really what we need.
@@ -152,7 +152,7 @@
if (hasLayout)
{
in.ensureBytes(9); //1 + 2 + 2 + 2 + 2
- _alignment =
static_cast<TextField::TextAlignment>(in.read_u8());
+ _alignment =
static_cast<TextField_as::TextAlignment>(in.read_u8());
_leftMargin = in.read_u16();
_rightMargin = in.read_u16();
_indent = in.read_s16();
@@ -191,7 +191,7 @@
_fontID(-1),
_textHeight(1),
_maxChars(0),
- _alignment(TextField::ALIGN_LEFT),
+ _alignment(TextField_as::ALIGN_LEFT),
_leftMargin(0),
_rightMargin(0),
_indent(0),
=== modified file 'libcore/swf/DefineEditTextTag.h'
--- a/libcore/swf/DefineEditTextTag.h 2009-04-15 09:08:37 +0000
+++ b/libcore/swf/DefineEditTextTag.h 2009-06-08 22:24:55 +0000
@@ -26,7 +26,7 @@
#include "DefinitionTag.h"
#include "swf.h" // for TagType definition
#include "RGBA.h"
-#include "TextField.h"
+#include "text/TextField_as.h"
#include <boost/cstdint.hpp> // for boost::uint16_t and friends
@@ -135,7 +135,7 @@
}
/// Get text alignment
- TextField::TextAlignment alignment() const {
+ TextField_as::TextAlignment alignment() const {
return _alignment;
}
@@ -277,7 +277,7 @@
///
unsigned int _maxChars;
- TextField::TextAlignment _alignment;
+ TextField_as::TextAlignment _alignment;
/// extra space between box's left border and text (in twips)
boost::uint16_t _leftMargin;
=== modified file 'testsuite/as3/classes.all/text/TextField_as.hx'
--- a/testsuite/as3/classes.all/text/TextField_as.hx 2009-06-02 22:39:40
+0000
+++ b/testsuite/as3/classes.all/text/TextField_as.hx 2009-06-08 22:24:55
+0000
@@ -1,6 +1,6 @@
// TextField_as.hx: ActionScript 3 "TextField" class, for Gnash.
//
-// Generated by gen-as3.sh on: 20090515 by "rob". Remove this
+// Generated on: 20090608 by "bnaugle". Remove this
// after any hand editing loosing changes.
//
// Copyright (C) 2009 Free Software Foundation, Inc.
@@ -32,6 +32,7 @@
#else
import flash.TextField;
import flash.MovieClip;
+import flash.text.StyleSheet;
#end
import flash.Lib;
import Type;
@@ -43,16 +44,14 @@
// Class must be named with the _as suffix, as that's the same name as the
file.
class TextField_as {
static function main() {
-
+#if !(flash6 || flash7)
#if flash9
var x1:TextField = new TextField();
#else
- var x1:TextField;
+ var x1:TextField =
flash.Lib.current.createTextField("",10,0,0,300,300);
#end
-
-#if flash9
// Make sure we actually get a valid class
- if (Type.typeof(TextField)==TObject && x1 != null) {
+ if (Std.is(x1, TextField)) {
DejaGnu.pass("TextField class exists");
} else {
DejaGnu.fail("TextField class doesn't exist");
@@ -60,22 +59,13 @@
// Tests to see if all the properties exist. All these do is test for
// existance of a property, and don't test the functionality at all. This
// is primarily useful only to test completeness of the API implementation.
-
+#if flash9
if (Type.typeof(x1.alwaysShowSelection) == TBool) {
DejaGnu.pass("TextField.alwaysShowSelection property exists");
} else {
DejaGnu.fail("TextField.alwaysShowSelection property doesn't
exist");
}
- if (Std.is(x1.antiAliasType,String) ) {
- DejaGnu.pass("TextField.antiAliasType property exists");
- } else {
- DejaGnu.fail("TextField.antiAliasType property doesn't exist");
- }
- if (Std.is(x1.antiAliasType,String) ) {
- DejaGnu.pass("TextField.antiAliasType property exists");
- } else {
- DejaGnu.fail("TextField.antiAliasType property doesn't exist");
- }
+#end
if (Std.is(x1.autoSize,String) ) {
DejaGnu.pass("TextField.autoSize property exists");
} else {
@@ -86,7 +76,7 @@
} else {
DejaGnu.fail("TextField.background property doesn't exist");
}
- if (Std.is(x1.backgroundColor,Float) ) {
+ if (Std.is(x1.backgroundColor,Int) ) {
DejaGnu.pass("TextField.backgroundColor property exists");
} else {
DejaGnu.fail("TextField.backgroundColor property doesn't exist");
@@ -101,6 +91,7 @@
} else {
DejaGnu.fail("TextField.borderColor property doesn't exist");
}
+#if flash9
if (Std.is(x1.bottomScrollV,Float) ) {
DejaGnu.pass("TextField.bottomScrollV property exists");
} else {
@@ -111,11 +102,6 @@
} else {
DejaGnu.fail("TextField.caretIndex property doesn't exist");
}
- if (Type.typeof(x1.condenseWhite)== TBool) {
- DejaGnu.pass("TextField.condenseWhite property exists");
- } else {
- DejaGnu.fail("TextField.condenseWhite property doesn't exist");
- }
if (Std.is(x1.defaultTextFormat,TextFormat) ) {
DejaGnu.pass("TextField.defaultTextFormat property exists");
} else {
@@ -126,31 +112,11 @@
} else {
DejaGnu.fail("TextField.displayAsPassword property doesn't exist");
}
- if (Type.typeof(x1.embedFonts) == TBool) {
- DejaGnu.pass("TextField.embedFonts property exists");
- } else {
- DejaGnu.fail("TextField.embedFonts property doesn't exist");
- }
- if (Std.is(x1.gridFitType,String) ) {
- DejaGnu.pass("TextField.gridFitType property exists");
- } else {
- DejaGnu.fail("TextField.gridFitType property doesn't exist");
- }
if (Std.is(x1.htmlText,String) ) {
DejaGnu.pass("TextField.htmlText property exists");
} else {
DejaGnu.fail("TextField.htmlText property doesn't exist");
}
- if (Std.is(x1.length,Int) ) {
- DejaGnu.pass("TextField.length property exists");
- } else {
- DejaGnu.fail("TextField.length property doesn't exist");
- }
- if (Std.is(x1.maxChars,Int) ) {
- DejaGnu.pass("TextField.maxChars property exists");
- } else {
- DejaGnu.fail("TextField.maxChars property doesn't exist");
- }
if (Std.is(x1.maxScrollH,Int) ) {
DejaGnu.pass("TextField.maxScrollH property exists");
} else {
@@ -161,27 +127,6 @@
} else {
DejaGnu.fail("TextField.maxScrollV property doesn't exist");
}
- if (Type.typeof(x1.mouseWheelEnabled) == TBool) {
- DejaGnu.pass("TextField.mouseWheelEnabled property exists");
- } else {
- DejaGnu.fail("TextField.mouseWheelEnabled property doesn't exist");
- }
- if (Type.typeof(x1.multiline)==TBool ) {
- DejaGnu.pass("TextField.multiline property exists");
- } else {
- DejaGnu.fail("TextField.multiline property doesn't exist");
- }
- if (Std.is(x1.numLines,Int) ) {
- DejaGnu.pass("TextField.numLines property exists");
- } else {
- DejaGnu.fail("TextField.numLines property doesn't exist");
- }
-// if (Std.is(x1.restrict,String) ) {
-// DejaGnu.pass("TextField.restrict property exists");
-// } else {
-// DejaGnu.fail("TextField.restrict property doesn't exist");
-// }
-
if (Std.is(x1.scrollH,Int) ) {
DejaGnu.pass("TextField.scrollH property exists");
} else {
@@ -192,10 +137,10 @@
} else {
DejaGnu.fail("TextField.scrollV property doesn't exist");
}
- if (Type.typeof(x1.selectable)==TBool ) {
- DejaGnu.pass("TextField.selectable property exists");
+ if (Std.is(x1.numLines,Int) ) {
+ DejaGnu.pass("TextField.numLines property exists");
} else {
- DejaGnu.fail("TextField.selectable property doesn't exist");
+ DejaGnu.fail("TextField.numLines property doesn't exist");
}
if (Std.is(x1.selectionBeginIndex,Int) ) {
DejaGnu.pass("TextField.selectionBeginIndex property exists");
@@ -206,12 +151,108 @@
DejaGnu.pass("TextField.selectionEndIndex property exists");
} else {
DejaGnu.fail("TextField.selectionEndIndex property doesn't exist");
- }
+ }
+ if (Type.typeof(x1.useRichTextClipboard) == TBool) {
+ DejaGnu.pass("TextField.useRichTextClipboard property exists");
+ } else {
+ DejaGnu.fail("TextField.useRichTextClipboard property doesn't
exist");
+ }
+#else
+ if (Type.typeof(x1.password) == TBool) {
+ DejaGnu.pass("TextField.password property exists");
+ } else {
+ DejaGnu.fail("TextField.password property doesn't exist");
+ }
+ if (Std.is(x1.bottomScroll,Float) ) {
+ DejaGnu.pass("TextField.bottomScroll property exists");
+ } else {
+ DejaGnu.fail("TextField.bottomScroll property doesn't exist");
+ }
+ if (Std.is(x1.maxhscroll,Int) ) {
+ DejaGnu.pass("TextField.maxhscroll property exists");
+ } else {
+ DejaGnu.fail("TextField.maxhscroll property doesn't exist");
+ }
+ if (Std.is(x1.maxscroll,Int) ) {
+ DejaGnu.pass("TextField.maxscroll property exists");
+ } else {
+ DejaGnu.fail("TextField.maxscroll property doesn't exist");
+ }
+ if (Std.is(x1.scroll,Int) ) {
+ DejaGnu.pass("TextField.scroll property exists");
+ } else {
+ DejaGnu.fail("TextField.scroll property doesn't exist");
+ }
+ if (Std.is(x1.html,Bool) ) {
+ DejaGnu.pass("TextField.html property exists");
+ } else {
+ DejaGnu.fail("TextField.html property doesn't exist");
+ }
+#end
+#if (flash9 || flash8)
+ if (Std.is(x1.antiAliasType,String) ) {
+ DejaGnu.pass("TextField.antiAliasType property exists");
+ } else {
+ DejaGnu.fail("TextField.antiAliasType property doesn't exist");
+ }
if (Std.is(x1.sharpness,Float) ) {
DejaGnu.pass("TextField.sharpness property exists");
} else {
DejaGnu.fail("TextField.sharpness property doesn't exist");
}
+ if (Std.is(x1.gridFitType,String) ) {
+ DejaGnu.pass("TextField.gridFitType property exists");
+ } else {
+ DejaGnu.fail("TextField.gridFitType property doesn't exist");
+ }
+ if (Std.is(x1.thickness,Float) ){
+ DejaGnu.pass("TextField.thickness property exists");
+ } else {
+ DejaGnu.fail("TextField.thickness property doesn't exist");
+ }
+#end
+ if (Type.typeof(x1.condenseWhite)== TBool) {
+ DejaGnu.pass("TextField.condenseWhite property exists");
+ } else {
+ DejaGnu.fail("TextField.condenseWhite property doesn't exist");
+ }
+ if (Type.typeof(x1.embedFonts) == TBool) {
+ DejaGnu.pass("TextField.embedFonts property exists");
+ } else {
+ DejaGnu.fail("TextField.embedFonts property doesn't exist");
+ }
+ if (Std.is(x1.length,Int) ) {
+ DejaGnu.pass("TextField.length property exists");
+ } else {
+ DejaGnu.fail("TextField.length property doesn't exist");
+ }
+ if (Std.is(x1.maxChars,Int) ) {
+ DejaGnu.pass("TextField.maxChars property exists");
+ } else {
+ DejaGnu.fail("TextField.maxChars property doesn't exist");
+ }
+ if (Type.typeof(x1.mouseWheelEnabled) == TBool) {
+ DejaGnu.pass("TextField.mouseWheelEnabled property exists");
+ } else {
+ DejaGnu.fail("TextField.mouseWheelEnabled property doesn't exist");
+ }
+ if (Type.typeof(x1.multiline)==TBool ) {
+ DejaGnu.pass("TextField.multiline property exists");
+ } else {
+ DejaGnu.fail("TextField.multiline property doesn't exist");
+ }
+// if (Std.is(x1.restrict,String) ) {
+// DejaGnu.pass("TextField.restrict property exists");
+// } else {
+// DejaGnu.fail("TextField.restrict property doesn't exist");
+// }
+
+
+ if (Type.typeof(x1.selectable)==TBool ) {
+ DejaGnu.pass("TextField.selectable property exists");
+ } else {
+ DejaGnu.fail("TextField.selectable property doesn't exist");
+ }
//Si:
//I initialized the StylsSheet at first
@@ -245,29 +286,16 @@
} else {
DejaGnu.fail("TextField.textWidth property doesn't exist");
}
- if (Std.is(x1.thickness,Float) ){
- DejaGnu.pass("TextField.thickness property exists");
- } else {
- DejaGnu.fail("TextField.thickness property doesn't exist");
- }
if (Std.is(x1.type,String) ) {
DejaGnu.pass("TextField.type property exists");
} else {
DejaGnu.fail("TextField.type property doesn't exist");
}
- if (Type.typeof(x1.useRichTextClipboard) == TBool) {
- DejaGnu.pass("TextField.useRichTextClipboard property exists");
- } else {
- DejaGnu.fail("TextField.useRichTextClipboard property doesn't
exist");
- }
if (Type.typeof(x1.wordWrap)== TBool) {
DejaGnu.pass("TextField.wordWrap property exists");
} else {
DejaGnu.fail("TextField.wordWrap property doesn't exist");
}
-#else
-#end
-
//Si:
//This one is not defined in Haxe
@@ -282,11 +310,6 @@
// existance of a method, and don't test the functionality at all. This
// is primarily useful only to test completeness of the API implementation.
#if flash9
-// if (Type.typeof(x1.TextField)==TFunction) {
-// DejaGnu.pass("TextField::TextField() method exists");
-// } else {
-// DejaGnu.fail("TextField::TextField() method doesn't exist");
-// }
if (Type.typeof(x1.appendText)==TFunction) {
DejaGnu.pass("TextField::appendText() method exists");
} else {
@@ -362,7 +385,6 @@
} else {
DejaGnu.fail("TextField::getTexRuns() method doesn't exist");
}
-
if (Type.typeof(x1.getXMLText )==TFunction) {
DejaGnu.pass("TextField::getXMLText() method exists");
} else {
@@ -373,31 +395,30 @@
} else {
DejaGnu.fail("TextField::insertXMLText() method doesn't exist");
}
-
-
if (Type.typeof(x1.replaceSelectedText )==TFunction) {
DejaGnu.pass("TextField::replaceSelectedText() method exists");
} else {
DejaGnu.fail("TextField::replaceSelectedText() method doesn't
exist");
}
+ if (Type.typeof(x1.setSelection )==TFunction) {
+ DejaGnu.pass("TextField::setSelection() method exists");
+ } else {
+ DejaGnu.fail("TextField::setSelection() method doesn't exist");
+ }
+#else
+
+#end
if (Type.typeof(x1.replaceText)==TFunction) {
DejaGnu.pass("TextField::replaceText() method exists");
} else {
DejaGnu.fail("TextField::replaceText() method doesn't exist");
}
- if (Type.typeof(x1.setSelection )==TFunction) {
- DejaGnu.pass("TextField::setSelection() method exists");
- } else {
- DejaGnu.fail("TextField::setSelection() method doesn't exist");
- }
if (Type.typeof(x1.setTextFormat )==TFunction) {
DejaGnu.pass("TextField::setTextFormat() method exists");
} else {
DejaGnu.fail("TextField::setTextFormat() method doesn't exist");
}
-#else
#end
-
// Call this after finishing all tests. It prints out the totals.
DejaGnu.done();
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r11043: Merge from branch,
Bob Naugle <=