gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r10660: Test and partly implement Te


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10660: Test and partly implement TextSnapshot class.
Date: Thu, 05 Mar 2009 17:24:37 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10660
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Thu 2009-03-05 17:24:37 +0100
message:
  Test and partly implement TextSnapshot class.
added:
  testsuite/misc-ming.all/TextSnapshotTest.c
modified:
  libcore/Font.cpp
  libcore/Font.h
  libcore/MovieClip.cpp
  libcore/asobj/Error_as.cpp
  libcore/asobj/TextSnapshot_as.cpp
  libcore/asobj/TextSnapshot_as.h
  libcore/character.h
  libcore/generic_character.cpp
  libcore/generic_character.h
  libcore/parser/character_def.h
  libcore/swf/DefineEditTextTag.h
  libcore/swf/DefineTextTag.cpp
  libcore/swf/DefineTextTag.h
  testsuite/actionscript.all/TextSnapshot.as
  testsuite/misc-ming.all/Makefile.am
    ------------------------------------------------------------
    revno: 10659.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 09:57:36 +0100
    message:
      Initial tests for TextSnapshot.
    added:
      testsuite/misc-ming.all/TextSnapshotTest.c
    modified:
      testsuite/misc-ming.all/Makefile.am
    ------------------------------------------------------------
    revno: 10659.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 10:16:32 +0100
    message:
      Clean up header.
    modified:
      libcore/swf/DefineEditTextTag.h
    ------------------------------------------------------------
    revno: 10659.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 10:16:53 +0100
    message:
      Code cleanups.
    modified:
      libcore/Font.cpp
      libcore/Font.h
    ------------------------------------------------------------
    revno: 10659.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 11:58:01 +0100
    message:
      Implement reverse lookup in code table, that is, return the unicode 
character
      of a given glyph. This is for TextSnapshot, which is certainly implemented
      as a special class/method of MovieClip because doing this is inefficient.
    modified:
      libcore/Font.cpp
      libcore/Font.h
    ------------------------------------------------------------
    revno: 10659.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 12:00:05 +0100
    message:
      Add virtual getStaticText() to character class for retrieving a string 
from
      static text fields.
      
      Add virtual extractStaticText() to character_def for querying definitions 
for 
      static text.
      
      Implement extractStaticText in DefineTextTag. It uses 
Font::codeTableLookup().
      
      Add MovieClip::getTextSnapshot() to query the display list for static 
text,
      which is then added to a string.
    modified:
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/character.h
      libcore/generic_character.cpp
      libcore/generic_character.h
      libcore/parser/character_def.h
      libcore/swf/DefineTextTag.cpp
      libcore/swf/DefineTextTag.h
    ------------------------------------------------------------
    revno: 10659.1.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 12:14:47 +0100
    message:
      Check that TextSnapshot can't be constructed with a string arg either.
    modified:
      testsuite/actionscript.all/TextSnapshot.as
    ------------------------------------------------------------
    revno: 10659.1.7
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 12:28:26 +0100
    message:
      Implement TextSnapshot constructor. This isn't ideal, but like many other
      classes works for the majority of cases.
    modified:
      libcore/MovieClip.cpp
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10659.1.8
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 15:03:05 +0100
    message:
      More tests for TextSnapshot.
      
      Rework so that a pointer to all static Text character is kept in
      TextSnapshot_as. This is necessary for highlighting, which will
      require either access to the TextRecords or transform information (or 
both).
      
      Implement getText() and getCount() properly.
    modified:
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      libcore/character.h
      libcore/generic_character.cpp
      libcore/generic_character.h
      libcore/parser/character_def.h
      libcore/swf/DefineTextTag.cpp
      libcore/swf/DefineTextTag.h
      testsuite/actionscript.all/TextSnapshot.as
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10659.1.9
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 15:48:15 +0100
    message:
      Get VM from fn_call.
    modified:
      libcore/asobj/Error_as.cpp
    ------------------------------------------------------------
    revno: 10659.1.10
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 15:48:57 +0100
    message:
      Add tests for overridden TextSnapshot.
    modified:
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10659.1.11
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 16:10:14 +0100
    message:
      Consolidate and clean up constructor code.
    modified:
      libcore/MovieClip.cpp
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10659.1.12
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 16:30:33 +0100
    message:
      Minor fixes, xcheck->check.
    modified:
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      testsuite/actionscript.all/TextSnapshot.as
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10659.1.13
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-03-05 16:47:09 +0100
    message:
      Make TextSnapshotTest-Runner run in make check.
    modified:
      testsuite/misc-ming.all/Makefile.am
=== modified file 'libcore/Font.cpp'
--- a/libcore/Font.cpp  2009-02-09 03:22:05 +0000
+++ b/libcore/Font.cpp  2009-03-05 10:58:01 +0000
@@ -31,6 +31,26 @@
 
 namespace gnash {
 
+namespace {
+
+/// Reverse lookup of Glyph in CodeTable.
+//
+/// Inefficient, which is probably why TextSnapshot was designed like it
+/// is.
+class CodeLookup
+{
+public:
+    CodeLookup(const int glyph) : _glyph(glyph) {}
+
+    bool operator()(const std::pair<const boost::uint16_t, int>& p) {
+        return p.second == _glyph;
+    }
+
+private:
+    int _glyph;
+};
+
+}
 
 Font::GlyphInfo::GlyphInfo()
        :
@@ -171,6 +191,19 @@
     _name = name;
 }
 
+
+boost::uint16_t
+Font::codeTableLookup(int glyph, bool embedded) const
+{
+    const CodeTable& ctable = (embedded && _embeddedCodeTable) ? 
+        *_embeddedCodeTable : _deviceCodeTable;
+    
+    CodeTable::const_iterator it = std::find_if(ctable.begin(), ctable.end(),
+            CodeLookup(glyph));
+    assert (it != ctable.end());
+    return it->first;
+}
+
 int
 Font::get_glyph_index(boost::uint16_t code, bool embedded) const
 {
@@ -185,7 +218,7 @@
         return glyph_index;
     }
 
-    // Try adding an os font, of possible
+    // Try adding an os font, if possible
     if ( ! embedded )
     {
         glyph_index = const_cast<Font*>(this)->add_os_glyph(code);

=== modified file 'libcore/Font.h'
--- a/libcore/Font.h    2009-02-09 03:22:05 +0000
+++ b/libcore/Font.h    2009-03-05 10:58:01 +0000
@@ -51,30 +51,22 @@
 public:
        boost::uint16_t m_char0, m_char1;
 
-       bool    operator==(const kerning_pair& k) const
+       bool operator==(const kerning_pair& k) const
        {
                return m_char0 == k.m_char0 && m_char1 == k.m_char1;
        }
-
-
 };
 
 // for use in standard algorithms
-inline bool operator< (const kerning_pair& p1, const kerning_pair& p2)
+inline bool
+operator< (const kerning_pair& p1, const kerning_pair& p2)
 {
-       if ( p1.m_char0 < p2.m_char0 )
-       {
-               return true;
-       }
-       else if ( p1.m_char0 == p2.m_char0 )
-       {
-               if ( p1.m_char1 < p2.m_char1 ) return true;
-               else return false;
-       }
-       else
-       {
-               return false;
-       }
+       if (p1.m_char0 < p2.m_char0) return true;
+       if (p1.m_char0 == p2.m_char0) {
+               if (p1.m_char1 < p2.m_char1) return true;
+    }
+    
+    return false;
 }
 
 /// \brief
@@ -106,6 +98,8 @@
 
        ~Font();
 
+    boost::uint16_t codeTableLookup(int glyph, bool embedded) const;
+
        /// Return true if this font matches given name and flags
        //
        /// @param name
@@ -137,7 +131,7 @@
        ///     (would be a programming error most likely)
        ///
        ///
-       shape_character_def*    get_glyph(int glyph_index, bool embedded) const;
+       shape_character_def* get_glyph(int glyph_index, bool embedded) const;
 
        /// Get name of this font. 
        const std::string& get_name() const { return _name; }

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2009-03-03 16:26:50 +0000
+++ b/libcore/MovieClip.cpp     2009-03-05 16:24:37 +0000
@@ -58,7 +58,6 @@
 #include "flash/geom/Matrix_as.h"
 #include "ExportableResource.h"
 
-
 #ifdef USE_SWFTREE
 # include "tree.hh"
 #endif
@@ -201,23 +200,256 @@
 
 };
 
+/// Search the DisplayList for static text.
+class StaticTextFinder
+{
+public:
+    StaticTextFinder(std::string& to) : _to(to) {}
+
+    void operator()(character* ch) {
+        ch->getStaticText(_to);
+    }
+
+private:
+    std::string& _to;
+};
+
+/// Find a character hit by the given coordinates.
+//
+/// This class takes care about taking masks layers into
+/// account, but nested masks aren't properly tested yet.
+///
+class MouseEntityFinder
+{
+public:
+
+    /// @param wp
+    ///     Query point in world coordinate space
+    ///
+    /// @param pp
+    ///     Query point in parent coordinate space
+    ///
+MouseEntityFinder(point wp, point pp)
+        :
+        _highestHiddenDepth(std::numeric_limits<int>::min()),
+        _m(NULL),
+        _candidates(),
+        _wp(wp),
+        _pp(pp),
+        _checked(false)
+    {}
+
+    void operator() (character* ch)
+    {
+        assert(!_checked);
+        if ( ch->get_depth() <= _highestHiddenDepth )
+        {
+            if ( ch->isMaskLayer() )
+            {
+                log_debug(_("CHECKME: nested mask in MouseEntityFinder. "
+                            "This mask is %s at depth %d outer mask masked "
+                            "up to depth %d."),
+                            ch->getTarget(), ch->get_depth(),
+                            _highestHiddenDepth);
+                // Hiding mask still in effect...
+            }
+            return;
+        }
+
+        if ( ch->isMaskLayer() )
+        {
+            if ( ! ch->pointInShape(_wp.x, _wp.y) )
+            {
+#ifdef DEBUG_MOUSE_ENTITY_FINDING
+                log_debug(_("Character %s at depth %d is a mask not hitting "
+                        "the query point %g,%g and masking up to "
+                        "depth %d"), ch->getTarget(), ch->get_depth(), 
+                        _wp.x, _wp.y, ch->get_clip_depth());
+#endif
+                _highestHiddenDepth = ch->get_clip_depth();
+            }
+            else
+            {
+#ifdef DEBUG_MOUSE_ENTITY_FINDING
+                log_debug(_("Character %s at depth %d is a mask hitting the "
+                        "query point %g,%g"),
+                        ch->getTarget(), ch->get_depth(), _wp.x, _wp.y);
+#endif 
+            }
+            return;
+        }
+        if (! ch->isVisible()) return;
+
+        _candidates.push_back(ch);
+    }
+
+    void checkCandidates()
+    {
+        if (_checked) return;
+        for (Candidates::reverse_iterator i=_candidates.rbegin(),
+                        e=_candidates.rend(); i!=e; ++i) {
+            character* ch = *i;
+            character* te = ch->get_topmost_mouse_entity(_pp.x, _pp.y);
+            if (te) {
+                _m = te;
+                break;
+            }
+        }
+        _checked = true;
+    }
+
+    character* getEntity()
+    {
+        checkCandidates();
+#ifdef DEBUG_MOUSE_ENTITY_FINDING
+        if ( _m ) 
+        {
+            log_debug(_("MouseEntityFinder found character %s (depth %d) "
+                    "hitting point %g,%g"),
+                    _m->getTarget(), _m->get_depth(), _wp.x, _wp.y);
+        }
+#endif // DEBUG_MOUSE_ENTITY_FINDING
+        return _m;
+    }
+
+private:
+
+    /// Highest depth hidden by a mask
+    //
+    /// This will be -1 initially, and set
+    /// the the depth of a mask when the mask
+    /// doesn't contain the query point, while
+    /// scanning a DisplayList bottom-up
+    ///
+    int _highestHiddenDepth;
+
+    character* _m;
+
+    typedef std::vector<character*> Candidates;
+    Candidates _candidates;
+
+    /// Query point in world coordinate space
+    point    _wp;
+
+    /// Query point in parent coordinate space
+    point    _pp;
+
+    bool _checked;
+
+};
+
+/// Find the first character whose shape contain the point
+//
+/// Point coordinates in world TWIPS
+///
+class ShapeContainerFinder
+{
+public:
+
+    ShapeContainerFinder(boost::int32_t x, boost::int32_t y)
+        :
+        _found(false),
+        _x(x),
+        _y(y)
+    {}
+
+    bool operator() (character* ch) {
+        if (ch->pointInShape(_x, _y)) {
+            _found = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool hitFound() { return _found; }
+
+private:
+    bool _found;
+    boost::int32_t    _x;
+    boost::int32_t    _y;
+};
+
+/// Find the first visible character whose shape contain the point
+//
+/// Point coordinates in world TWIPS
+///
+class VisibleShapeContainerFinder
+{
+public:
+
+    VisibleShapeContainerFinder(boost::int32_t x, boost::int32_t    y)
+        :
+        _found(false),
+        _x(x),
+        _y(y)
+    {}
+
+    bool operator() (character* ch)
+    {
+        if (ch->pointInVisibleShape(_x, _y)) {
+            _found = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool hitFound() { return _found; }
+
+private:
+    bool _found;
+    boost::int32_t    _x;
+    boost::int32_t    _y;
+};
+
+/// Find the first hitable character whose shape contain the point 
+// 
+/// Point coordinates in world TWIPS 
+/// 
+class HitableShapeContainerFinder
+{ 
+public: 
+    HitableShapeContainerFinder(boost::int32_t x, boost::int32_t y) 
+            : 
+    _found(false), 
+    _x(x), 
+    _y(y) 
+    {} 
+
+    bool operator() (character* ch) 
+    { 
+        if (ch->isDynamicMask()) return true; 
+        if (ch->pointInShape(_x, _y)) {
+            _found = true; 
+            return false; 
+        } 
+        return true; 
+    } 
+
+    bool hitFound() { return _found; } 
+
+private:
+    bool _found; 
+    boost::int32_t _x; // TWIPS
+    boost::int32_t _y; // TWIPS
+}; 
+
 /// A DisplayList visitor used to compute its overall bounds.
 //
-class BoundsFinder {
+class BoundsFinder
+{
 public:
-    rect& _bounds;
-    BoundsFinder(rect& b)
-        :
-        _bounds(b)
-    {}
-    void operator() (character* ch)
-    {
+    BoundsFinder(rect& b) : _bounds(b) {}
+
+    void operator() (character* ch) {
         // don't include bounds of unloaded characters
         if ( ch->isUnloaded() ) return;
         rect chb = ch->getBounds();
         SWFMatrix m = ch->getMatrix();
         _bounds.expand_to_transformed_rect(m, chb);
     }
+
+private:
+    rect& _bounds;
 };
 
 /// A DisplayList visitor used to extract script characters
@@ -225,9 +457,8 @@
 /// Script characters are characters created or transformed
 /// by ActionScript. 
 ///
-class ScriptObjectsFinder {
-    std::vector<character*>& _dynamicChars;
-    std::vector<character*>& _staticChars;
+class ScriptObjectsFinder
+{
 public:
     ScriptObjectsFinder(std::vector<character*>& dynamicChars,
             std::vector<character*>& staticChars)
@@ -236,8 +467,7 @@
         _staticChars(staticChars)
     {}
 
-    void operator() (character* ch) 
-    {
+    void operator() (character* ch) {
         // don't include bounds of unloaded characters
         if ( ch->isUnloaded() ) return;
 
@@ -246,15 +476,15 @@
         //if ( ! ch->get_accept_anim_moves() )
         //if ( ch->isDynamic() )
         int depth = ch->get_depth();
-        if ( depth < character::lowerAccessibleBound || depth >= 0 )
-        {
+        if (depth < character::lowerAccessibleBound || depth >= 0) {
             _dynamicChars.push_back(ch);
         }
-        else
-        {
-            _staticChars.push_back(ch);
-        }
+        else _staticChars.push_back(ch);
     }
+
+private:
+    std::vector<character*>& _dynamicChars;
+    std::vector<character*>& _staticChars;
 };
 
 } // anonymous namespace
@@ -1483,236 +1713,6 @@
     return can_handle_mouse_event();
 }
 
-/// Find a character hit by the given coordinates.
-//
-/// This class takes care about taking masks layers into
-/// account, but nested masks aren't properly tested yet.
-///
-class MouseEntityFinder {
-
-    /// Highest depth hidden by a mask
-    //
-    /// This will be -1 initially, and set
-    /// the the depth of a mask when the mask
-    /// doesn't contain the query point, while
-    /// scanning a DisplayList bottom-up
-    ///
-    int _highestHiddenDepth;
-
-    character* _m;
-
-    typedef std::vector<character*> Candidates;
-    Candidates _candidates;
-
-    /// Query point in world coordinate space
-    point    _wp;
-
-    /// Query point in parent coordinate space
-    point    _pp;
-
-    bool _checked;
-
-public:
-
-    /// @param wp
-    ///     Query point in world coordinate space
-    ///
-    /// @param pp
-    ///     Query point in parent coordinate space
-    ///
- MouseEntityFinder(point    wp, point    pp)
-        :
-        _highestHiddenDepth(std::numeric_limits<int>::min()),
-        _m(NULL),
-        _candidates(),
-        _wp(wp),
-        _pp(pp),
-        _checked(false)
-    {}
-
-    void operator() (character* ch)
-    {
-        assert(!_checked);
-        if ( ch->get_depth() <= _highestHiddenDepth )
-        {
-            if ( ch->isMaskLayer() )
-            {
-                log_debug(_("CHECKME: nested mask in MouseEntityFinder. "
-                            "This mask is %s at depth %d outer mask masked "
-                            "up to depth %d."),
-                            ch->getTarget(), ch->get_depth(),
-                            _highestHiddenDepth);
-                // Hiding mask still in effect...
-            }
-            return;
-        }
-
-        if ( ch->isMaskLayer() )
-        {
-            if ( ! ch->pointInShape(_wp.x, _wp.y) )
-            {
-#ifdef DEBUG_MOUSE_ENTITY_FINDING
-                log_debug(_("Character %s at depth %d is a mask not hitting "
-                        "the query point %g,%g and masking up to "
-                        "depth %d"), ch->getTarget(), ch->get_depth(), 
-                        _wp.x, _wp.y, ch->get_clip_depth());
-#endif
-                _highestHiddenDepth = ch->get_clip_depth();
-            }
-            else
-            {
-#ifdef DEBUG_MOUSE_ENTITY_FINDING
-                log_debug(_("Character %s at depth %d is a mask hitting the "
-                        "query point %g,%g"),
-                        ch->getTarget(), ch->get_depth(), _wp.x, _wp.y);
-#endif 
-            }
-
-            return;
-        }
-
-        if ( ! ch->isVisible() ) return;
-
-        _candidates.push_back(ch);
-
-    }
-
-    void checkCandidates()
-    {
-        if ( _checked ) return;
-        for (Candidates::reverse_iterator i=_candidates.rbegin(),
-                        e=_candidates.rend(); i!=e; ++i)
-        {
-            character* ch = *i;
-            character* te = ch->get_topmost_mouse_entity(_pp.x, _pp.y);
-            if ( te )
-            {
-                _m = te;
-                break;
-            }
-        }
-        _checked = true;
-    }
-
-    character* getEntity()
-    {
-        checkCandidates();
-#ifdef DEBUG_MOUSE_ENTITY_FINDING
-        if ( _m ) 
-        {
-            log_debug(_("MouseEntityFinder found character %s (depth %d) "
-                    "hitting point %g,%g"),
-                    _m->getTarget(), _m->get_depth(), _wp.x, _wp.y);
-        }
-#endif // DEBUG_MOUSE_ENTITY_FINDING
-        return _m;
-    }
-        
-};
-
-/// Find the first character whose shape contain the point
-//
-/// Point coordinates in world TWIPS
-///
-class ShapeContainerFinder {
-
-    bool _found;
-    boost::int32_t    _x;
-    boost::int32_t    _y;
-
-public:
-
-    ShapeContainerFinder(boost::int32_t x, boost::int32_t y)
-        :
-        _found(false),
-        _x(x),
-        _y(y)
-    { }
-
-    bool operator() (character* ch)
-    {
-        if ( ch->pointInShape(_x, _y) )
-        {
-            _found = true;
-            return false;
-        }
-        else return true;
-    }
-
-    bool hitFound() { return _found; }
-        
-};
-
-/// Find the first visible character whose shape contain the point
-//
-/// Point coordinates in world TWIPS
-///
-class VisibleShapeContainerFinder {
-
-    bool _found;
-    boost::int32_t    _x;
-    boost::int32_t    _y;
-
-public:
-
-    VisibleShapeContainerFinder(boost::int32_t x, boost::int32_t    y)
-        :
-        _found(false),
-        _x(x),
-        _y(y)
-    {}
-
-    bool operator() (character* ch)
-    {
-        if ( ch->pointInVisibleShape(_x, _y) )
-        {
-            _found = true;
-            return false;
-        }
-        else return true;
-    }
-
-    bool hitFound() { return _found; }
-        
-};
-
-/// Find the first hitable character whose shape contain the point 
-// 
-/// Point coordinates in world TWIPS 
-/// 
-class HitableShapeContainerFinder { 
-    bool _found; 
-    boost::int32_t    _x; // TWIPS
-    boost::int32_t    _y; // TWIPS
-        
-public: 
-    HitableShapeContainerFinder(boost::int32_t x, boost::int32_t y) 
-            : 
-    _found(false), 
-    _x(x), 
-    _y(y) 
-    {} 
-
-    bool operator() (character* ch) 
-    { 
-        if( ch->isDynamicMask() ) 
-        { 
-            return true; 
-        } 
-        else if ( ch->pointInShape(_x, _y) ) 
-        {
-            _found = true; 
-            return false; 
-        } 
-        else 
-        { 
-            return true; 
-        }
-    } 
-
-    bool hitFound() { return _found; } 
-}; 
-
 bool
 MovieClip::pointInShape(boost::int32_t x, boost::int32_t y) const
 {
@@ -4059,11 +4059,29 @@
 as_value
 movieclip_getTextSnapshot(const fn_call& fn)
 {
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    LOG_ONCE( log_unimpl("MovieClip.getTextSnapshot()") );
-    return as_value();
+    boost::intrusive_ptr<MovieClip> obj = ensureType<MovieClip>(fn.this_ptr);
+
+    // If not found, construction fails.
+    as_value textSnapshot(fn.env().find_object("TextSnapshot"));
+
+    boost::intrusive_ptr<as_function> tsCtor = textSnapshot.to_as_function();
+
+    if (!tsCtor) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror("MovieClip.getTextSnapshot: failed to construct "
+                "TextSnapshot (object probably overridden)");
+        );
+        return as_value();
+    }
+
+    // Construct a flash.geom.Transform object with "this" as argument.
+    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+    args->push_back(obj.get());
+
+    boost::intrusive_ptr<as_object> ts =
+        tsCtor->constructInstance(fn.env(), args);
+
+    return as_value(ts.get());
 }
 
 

=== modified file 'libcore/asobj/Error_as.cpp'
--- a/libcore/asobj/Error_as.cpp        2009-01-22 20:10:39 +0000
+++ b/libcore/asobj/Error_as.cpp        2009-03-05 14:48:15 +0000
@@ -121,7 +121,7 @@
 
        boost::intrusive_ptr<Error_as> err = new Error_as;
        
-    string_table& st = err->getVM().getStringTable();
+    string_table& st = fn.getVM().getStringTable();
     if (fn.nargs > 0)
        {
                err->set_member(st.find("message"), fn.arg(0));

=== modified file 'libcore/asobj/TextSnapshot_as.cpp'
--- a/libcore/asobj/TextSnapshot_as.cpp 2009-03-04 18:28:12 +0000
+++ b/libcore/asobj/TextSnapshot_as.cpp 2009-03-05 15:30:33 +0000
@@ -28,6 +28,11 @@
 #include "smart_ptr.h" // for boost intrusive_ptr
 #include "builtin_function.h" // need builtin_function
 #include "Object.h" // for getObjectInterface
+#include "generic_character.h"
+#include "DisplayList.h"
+#include "MovieClip.h"
+
+#include <algorithm>
 
 namespace gnash {
 
@@ -47,13 +52,87 @@
 
     void attachTextSnapshotInterface(as_object& o);
     as_object* getTextSnapshotInterface();
+
+    void setTextReachable( const TextSnapshot_as::TextFields::value_type& vt);
+
 }
 
-TextSnapshot_as::TextSnapshot_as()
+namespace {
+
+class TextFinder
+{
+public:
+    TextFinder(TextSnapshot_as::TextFields& fields) : _fields(fields) {}
+
+    void operator()(character* ch) {
+        if (ch->isUnloaded()) return;
+        std::string text;
+        generic_character* tf;
+        if ((tf = ch->getStaticText(text))) {
+            _fields.push_back(std::make_pair(tf, text));
+        }
+    }
+
+private:
+        TextSnapshot_as::TextFields& _fields;
+};
+
+} // anonymous namespace
+
+
+TextSnapshot_as::TextSnapshot_as(const MovieClip* mc)
     :
-    as_object(getTextSnapshotInterface())
-{
-}
+    as_object(getTextSnapshotInterface()),
+    _valid(mc)
+{
+    if (mc) {
+        const DisplayList& dl = mc->getDisplayList();
+
+        TextFinder finder(_textFields);
+        dl.visitAll(finder);
+    }
+}
+
+void
+TextSnapshot_as::markReachableResources() const
+{
+    std::for_each(_textFields.begin(), _textFields.end(), setTextReachable);
+}
+
+void
+TextSnapshot_as::makeString(std::string& to, bool newline) const
+{
+    for (TextFields::const_iterator it = _textFields.begin(),
+            e = _textFields.end(); it != e; ++it)
+    {
+        if (newline && it != _textFields.begin()) to += '\n';
+        to += it->second;
+    }
+}
+
+const std::string
+TextSnapshot_as::getText(boost::int32_t start, boost::int32_t end, bool nl)
+    const
+{
+    std::string snapshot;
+    makeString(snapshot, nl);
+
+    const std::string::size_type len = snapshot.size();
+
+    if (len == 0) return std::string();
+
+    // Start is always moved to between 0 and len - 1.
+    start = std::max(start, 0);
+    start = std::min<std::string::size_type>(len - 1, start);
+
+    // End is always moved to between start and end. We don't really care
+    // about end.
+    end = std::max(start + 1, end);
+
+    return snapshot.substr(start, end - start);
+
+}
+
 
 void
 TextSnapshot_as::init(as_object& global)
@@ -66,7 +145,6 @@
                cl=new builtin_function(&textsnapshot_ctor, 
getTextSnapshotInterface());
        }
 
-       // Register _global.TextSnapshot
        global.init_member("TextSnapshot", cl.get());
 }
 
@@ -119,10 +197,27 @@
     log_unimpl (__FUNCTION__);
     return as_value();
 }
-as_value textsnapshot_getCount(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
-    return as_value();
+
+as_value
+textsnapshot_getCount(const fn_call& fn)
+{
+    boost::intrusive_ptr<TextSnapshot_as> ts =
+        ensureType<TextSnapshot_as>(fn.this_ptr);
+    
+    if (!ts->valid()) return as_value();
+
+    if (fn.nargs)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror("TextSnapshot.getCount takes no arguments");
+        );
+        return as_value();
+    }
+
+
+    return ts->getCount();
 }
+
 as_value textsnapshot_getSelected(const fn_call& /*fn*/) {
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -131,10 +226,33 @@
     log_unimpl (__FUNCTION__);
     return as_value();
 }
-as_value textsnapshot_getText(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
-    return as_value();
+
+as_value
+textsnapshot_getText(const fn_call& fn)
+{
+    boost::intrusive_ptr<TextSnapshot_as> ts =
+        ensureType<TextSnapshot_as>(fn.this_ptr);
+
+    if (!ts->valid()) return as_value();
+    
+    if (fn.nargs < 2 || fn.nargs > 3)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror("TextSnapshot.getText requires exactly 2 arguments");
+        );
+        return as_value();
+    }
+
+    boost::int32_t start = fn.arg(0).to_int();
+    boost::int32_t end = fn.arg(1).to_int();
+
+    const bool newline = (fn.nargs > 2) ? fn.arg(2).to_bool() : false;
+
+    return ts->getText(start, end, newline);
+
 }
+
+
 as_value textsnapshot_hitTestTextNearPos(const fn_call& /*fn*/) {
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -149,13 +267,17 @@
 }
 
 as_value
-textsnapshot_ctor(const fn_call& /* fn */)
-{
-       boost::intrusive_ptr<as_object> obj = new TextSnapshot_as;
-
-       return as_value(obj.get()); // will keep alive
-}
-
+textsnapshot_ctor(const fn_call& fn)
+{
+    MovieClip* mc = (fn.nargs == 1) ? fn.arg(0).to_sprite() : 0;
+    return as_value(new TextSnapshot_as(mc));
+}
+
+void
+setTextReachable(const TextSnapshot_as::TextFields::value_type& vt)
+{
+    vt.first->setReachable();
+}
 
 } // anonymous namespace
-} // end of gnash namespace
+} // gnash namespace

=== modified file 'libcore/asobj/TextSnapshot_as.h'
--- a/libcore/asobj/TextSnapshot_as.h   2009-03-04 17:52:33 +0000
+++ b/libcore/asobj/TextSnapshot_as.h   2009-03-05 15:30:33 +0000
@@ -23,14 +23,51 @@
 
 namespace gnash {
 
+class generic_character;
+
 class TextSnapshot_as: public as_object
 {
 
 public:
 
-       TextSnapshot_as();
+    /// Should remain in the order of insertion
+    /// We should only ever iterate from begin to end, so there's no
+    /// performance issue.
+    typedef std::vector<std::pair<generic_character*, std::string> > 
TextFields;
+
+    TextSnapshot_as(const MovieClip* mc);
+
+    std::string::size_type getCount() {
+        std::string snapshot;
+        makeString(snapshot);
+        return snapshot.size();
+    }
+
+    const std::string getText(boost::int32_t start, boost::int32_t end,
+            bool nl) const;
 
     static void init(as_object& global);
+
+    static void construct(const std::string& snapshot);
+
+    bool valid() const { return _valid; }
+
+protected:
+
+    void markReachableResources() const;
+
+private:
+
+    void makeString(std::string& to, bool newline = false) const;
+
+    TextFields _textFields;
+
+    /// Whether the object is valid, i.e. it was constructed with a MovieClip.
+    //
+    /// This should be deducible from another member, but since there seems
+    /// to be no point in storing the MovieClip this bool will do instead.
+    bool _valid;
+
 };
 
 } // end of gnash namespace

=== modified file 'libcore/character.h'
--- a/libcore/character.h       2009-01-26 09:04:28 +0000
+++ b/libcore/character.h       2009-03-05 14:03:05 +0000
@@ -49,6 +49,7 @@
   class ExecutableCode;
   class action_buffer;
   class movie_definition;
+  class generic_character;
 }
 
 namespace gnash {
@@ -408,7 +409,15 @@
     void add_event_handler(const event_id& id, const action_buffer& code);
 
     /// Render this character
-    virtual void    display() {}
+    virtual void display() {}
+
+    /// Allow extraction of static text.
+    //
+    /// Default is a no-op, implemented only for DefineText though
+    /// generic_character.
+    virtual generic_character* getStaticText(std::string& /*to*/) {
+        return 0;
+    }
 
     /// Returns local, untransformed height of this character in TWIPS
     //

=== modified file 'libcore/generic_character.cpp'
--- a/libcore/generic_character.cpp     2009-01-22 20:10:39 +0000
+++ b/libcore/generic_character.cpp     2009-03-05 14:03:05 +0000
@@ -48,6 +48,13 @@
 }
 
 
+generic_character*
+generic_character::getStaticText(std::string& to)
+{
+    if (m_def->extractStaticText(to)) return this;
+    return 0;
+}
+
 void  
 generic_character::display()
 {

=== modified file 'libcore/generic_character.h'
--- a/libcore/generic_character.h       2009-02-25 22:33:03 +0000
+++ b/libcore/generic_character.h       2009-03-05 14:03:05 +0000
@@ -72,6 +72,8 @@
                return false;
        }
 
+    virtual generic_character* getStaticText(std::string& to);
+
        virtual void display();
 
        rect getBounds() const

=== modified file 'libcore/parser/character_def.h'
--- a/libcore/parser/character_def.h    2009-02-09 03:22:05 +0000
+++ b/libcore/parser/character_def.h    2009-03-05 14:03:05 +0000
@@ -43,18 +43,14 @@
 ///
 class character_def : public ExportableResource
 {
-private:
-       int     m_id;
-               
-       // don't assign-to
-       character_def& operator= (const character_def&);
 public:
-       character_def()
+
+    character_def()
                :
-               m_id(-1),
-               m_render_cache(NULL)
-               {
-               }
+               m_render_cache(0),
+               _id(-1)
+    {
+    }
 
        
        virtual ~character_def();
@@ -63,7 +59,16 @@
        {
        }
 
-       /// Return true if the specified point is on the interior of our shape.
+    /// Return any text defined as static.
+    //
+    /// This is used for MovieClip.getTextSnapshot() and should only be
+    /// implemented in DefineTextTag. Default is a no-op
+    virtual bool extractStaticText(std::string& /*to*/)
+    {
+        return false;
+    }
+
+       /// Return true if the specified point is on the interior of our shape.
        //
        /// Point coordinates are local coords (TWIPS)
        ///
@@ -87,15 +92,13 @@
        // Declared as virtual here because generic_character needs access to it
        virtual const rect&     get_bound() const = 0;
        
-public:  
-  
-  /// Cache holder for renderer (contents depend on renderer handler)
-  /// Will be deleted by destructor of the character_def.
-  /// We could store by auto_ptr, but I'm afraid that would mean
-  /// including render_handler.h in this header, which I don't like.
-  /// (REF: PIMPL)
-  ///
-  render_cache_manager* m_render_cache;
+    /// Cache holder for renderer (contents depend on renderer handler)
+    /// Will be deleted by destructor of the character_def.
+    /// We could store by auto_ptr, but I'm afraid that would mean
+    /// including render_handler.h in this header, which I don't like.
+    /// (REF: PIMPL)
+    ///
+    render_cache_manager* m_render_cache;
 
 protected:
 
@@ -124,18 +127,23 @@
        character_def(const character_def& o)
                :
         ExportableResource(),
-               m_id(o.m_id),
-               m_render_cache(NULL)
+               m_render_cache(0),
+               _id(o._id)
        {}
 
+private:
+
+    int        _id;
+               
+       // don't assign-to
+       character_def& operator= (const character_def&);
        
 };
 
 
 }      // namespace gnash
 
-#endif // GNASH_CHARACTER_DEF_H
-
+#endif 
 
 // Local Variables:
 // mode: C++

=== modified file 'libcore/swf/DefineEditTextTag.h'
--- a/libcore/swf/DefineEditTextTag.h   2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineEditTextTag.h   2009-03-05 09:16:32 +0000
@@ -69,14 +69,6 @@
 
     character* create_character_instance(character* parent, int id);
 
-    /// How many of these are necessary?
-
-       /// Get width of this definition in twips (by definition)
-       //float width() const { return _rect.width(); }
-
-       /// Get height of this definition in twips (by definition)
-       //float height() const { return _rect.height(); }
-
        /// Return a reference to the default text associated
        /// with this EditText definition.
        const std::string& defaultText() const {

=== modified file 'libcore/swf/DefineTextTag.cpp'
--- a/libcore/swf/DefineTextTag.cpp     2009-01-05 09:32:03 +0000
+++ b/libcore/swf/DefineTextTag.cpp     2009-03-05 14:03:05 +0000
@@ -12,6 +12,7 @@
 #include "log.h"
 #include "swf.h"
 #include "TextRecord.h"
+#include "Font.h"
 
 namespace gnash {
 namespace SWF {
@@ -33,6 +34,36 @@
     m.add_character(id, t.release());
 }
 
+class DecodeRecord
+{
+public:
+
+    DecodeRecord(std::string& to) : _to(to) {}
+
+    void operator()(const TextRecord& tr) {
+
+        const Font* font = tr.getFont();
+        if (!font) return;
+        
+        const TextRecord::Glyphs& glyphs = tr.glyphs();
+
+        for (TextRecord::Glyphs::const_iterator it = glyphs.begin(),
+                e = glyphs.end(); it != e; ++it) {
+            _to += font->codeTableLookup(it->index, true);
+        }
+    }
+private:
+    std::string& _to;
+};
+
+
+bool
+DefineTextTag::extractStaticText(std::string& to)
+{
+    std::for_each(_textRecords.begin(), _textRecords.end(), DecodeRecord(to));
+    return true;
+}
+
 void
 DefineText2Tag::loader(SWFStream& in, TagType tag, movie_definition& m,
         const RunInfo& /*r*/)

=== modified file 'libcore/swf/DefineTextTag.h'
--- a/libcore/swf/DefineTextTag.h       2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineTextTag.h       2009-03-05 14:03:05 +0000
@@ -57,6 +57,9 @@
         return _rect; 
     }
 
+    /// Extract static text from TextRecords.
+    bool extractStaticText(std::string& to);
+
 private:
 
     /// DefineText2Tag::loader also constructs a DefineTextTag.

=== modified file 'testsuite/actionscript.all/TextSnapshot.as'
--- a/testsuite/actionscript.all/TextSnapshot.as        2009-03-04 17:52:33 
+0000
+++ b/testsuite/actionscript.all/TextSnapshot.as        2009-03-05 15:30:33 
+0000
@@ -69,8 +69,29 @@
  check_equals (typeof(textsnapshotObj.setSelectColor), 'function');
  check_equals (typeof(textsnapshotObj.setSelected), 'function');
 
+ gh = new TextSnapshot("hello");
+ check_equals(gh.toString(), "[object Object]");
+ check_equals(gh.getCount.toString(), "[type Function]");
+ check_equals(gh.getCount(), undefined);
+
+ o = {};
+ gh = new TextSnapshot(o);
+ check_equals(gh.toString(), "[object Object]");
+ check_equals(gh.getCount.toString(), "[type Function]");
+ check_equals(gh.getCount(), undefined);
+
+ gh = new TextSnapshot(this);
+ check_equals(gh.toString(), "[object Object]");
+ check_equals(gh.getCount.toString(), "[type Function]");
+ check_equals(gh.getCount(), 0);
+
+ gh = new TextSnapshot(this, true);
+ check_equals(gh.toString(), "[object Object]");
+ check_equals(gh.getCount.toString(), "[type Function]");
+ check_equals(gh.getCount(), undefined);
+
  ts = _root.getTextSnapshot();
- xcheck(ts instanceof TextSnapshot);
+ check(ts instanceof TextSnapshot);
  check(!ts.hasOwnProperty('findText'));
  check(!ts.hasOwnProperty('getCount'));
  check(!ts.hasOwnProperty('getSelected'));
@@ -82,12 +103,12 @@
 
  // getText() and getCount()
 
- xcheck_equals(typeof(ts.getCount()), "number");
+ check_equals(typeof(ts.getCount()), "number");
  check_equals(typeof(ts.getCount(0)), "undefined");
  check_equals(typeof(ts.getCount("a")), "undefined");
  check_equals(typeof(ts.getCount(true)), "undefined");
  check_equals(typeof(ts.getCount(0, 1)), "undefined");
- xcheck_equals(ts.getCount(), 0);
+ check_equals(ts.getCount(), 0);
 
  check_equals(typeof(ts.findText()), "undefined");
  check_equals(typeof(ts.findText("a")), "undefined");
@@ -117,7 +138,7 @@
  _root.createTextField("tf", 10, 30, 30, 100, 100);
  _root.tf.text = "ghjkab";
  ts = _root.getTextSnapshot();
- xcheck_equals(ts.getCount(), 0);
+ check_equals(ts.getCount(), 0);
  xcheck_equals(ts.findText(1, "a", true), -1);
  xcheck_equals(ts.findText(1, "a", false), -1);
 
@@ -162,16 +183,16 @@
  check_equals(typeof(ts.getText(0)), "undefined");
  check_equals(typeof(ts.getText("a")), "undefined");
  check_equals(typeof(ts.getText(new Date())), "undefined");
- xcheck_equals(typeof(ts.getText(0, 1)), "string");
- xcheck_equals(typeof(ts.getText(1, 0)), "string");
- xcheck_equals(typeof(ts.getText(-1, 3)), "string");
- xcheck_equals(typeof(ts.getText(1, 0)), "string");
- xcheck_equals(typeof(ts.getText(1, 0)), "string");
- xcheck_equals(typeof(ts.getText(0, "a")), "string");
- xcheck_equals(typeof(ts.getText("b", 0)), "string");
- xcheck_equals(typeof(ts.getText(true, false)), "string");
- xcheck_equals(typeof(ts.getText(0, 10, 10)), "string");
- xcheck_equals(typeof(ts.getText(0, 10, true)), "string");
+ check_equals(typeof(ts.getText(0, 1)), "string");
+ check_equals(typeof(ts.getText(1, 0)), "string");
+ check_equals(typeof(ts.getText(-1, 3)), "string");
+ check_equals(typeof(ts.getText(1, 0)), "string");
+ check_equals(typeof(ts.getText(1, 0)), "string");
+ check_equals(typeof(ts.getText(0, "a")), "string");
+ check_equals(typeof(ts.getText("b", 0)), "string");
+ check_equals(typeof(ts.getText(true, false)), "string");
+ check_equals(typeof(ts.getText(0, 10, 10)), "string");
+ check_equals(typeof(ts.getText(0, 10, true)), "string");
  check_equals(typeof(ts.getText(0, 10, "a", 11)), "undefined");
  check_equals(typeof(ts.getText(0, 10, 10, "hello")), "undefined");
  check_equals(typeof(ts.getText(0, 10, true, [3, 4])), "undefined");
@@ -222,6 +243,6 @@
  check_equals(typeof(ts.setSelected(0, 10, 10, "hello")), "undefined");
  check_equals(typeof(ts.setSelected(0, 10, true, [3, 4])), "undefined");
 
- totals(155);
+ totals(167);
 
 #endif // OUTPUT_VERSION > 5

=== modified file 'testsuite/misc-ming.all/Makefile.am'
--- a/testsuite/misc-ming.all/Makefile.am       2009-02-25 22:33:03 +0000
+++ b/testsuite/misc-ming.all/Makefile.am       2009-03-05 15:47:09 +0000
@@ -77,6 +77,7 @@
        SpriteButtonEventsTest-Runner \
        DefineTextTest \
        DefineTextTest-Runner \
+       TextSnapshotTest \
        DefineEditTextTest \
        DefineEditTextTest-Runner \
        DefineEditTextVariableNameTest \
@@ -237,6 +238,7 @@
 endif
 
 check_SCRIPTS = \
+       TextSnapshotTest-Runner \
        timeline_var_test-Runner \
        place_object_testrunner \
        place_object_test2runner \
@@ -391,6 +393,16 @@
        DefineTextTest.swf      \
        $(NULL)
 
+TextSnapshotTest.swf: TextSnapshotTest
+       ./TextSnapshotTest $(top_srcdir)/testsuite/media
+
+TextSnapshotTest_SOURCES =  TextSnapshotTest.c
+TextSnapshotTest_LDADD = libgnashmingutils.la
+
+TextSnapshotTest-Runner: $(srcdir)/../generic-testrunner.sh 
TextSnapshotTest.swf
+       sh $< $(top_builddir) TextSnapshotTest.swf > $@
+       chmod 755 $@
+
 DefineEditTextTest.swf: DefineEditTextTest
        ./DefineEditTextTest $(top_srcdir)/testsuite/media
 
@@ -1928,6 +1940,7 @@
        loadMovieTestRunner \
        eventSoundTest1-Runner \
        DrawingApiTestRunner \
+       TextSnapshotTest-Runner \
        action_execution_order_test1runner \
        action_execution_order_test2runner \
        action_execution_order_test3runner \

=== added file 'testsuite/misc-ming.all/TextSnapshotTest.c'
--- a/testsuite/misc-ming.all/TextSnapshotTest.c        1970-01-01 00:00:00 
+0000
+++ b/testsuite/misc-ming.all/TextSnapshotTest.c        2009-03-05 15:30:33 
+0000
@@ -0,0 +1,189 @@
+/* 
+ *   Copyright (C) 2005, 2006, 2007, 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
+ *
+ *
+ */ 
+
+/*
+ * Uses both "embedded" font and device fonts.
+ * The text written is 'Hello world' in both cases.
+ * Text at the bottom is the one with embedded fonts.
+ * 
+ * TODO: add a testrunner for pixel checking.
+ * TODO: test autoSize and wordWrap interaction (what takes precedence?)
+ *
+ * run as ./DefineEditTextTest
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ming.h>
+
+#include "ming_utils.h"
+
+#define OUTPUT_VERSION 8
+#define OUTPUT_FILENAME "TextSnapshotTest.swf"
+
+SWFDisplayItem
+add_text_field(SWFMovie mo, SWFFont font, const char* text);
+
+SWFDisplayItem
+add_text_field(SWFMovie mo, SWFFont font, const char* text)
+{
+  SWFText tf;
+
+  tf = newSWFText();
+
+  SWFText_setFont(tf, font);
+
+
+  SWFText_addString(tf, text, NULL);
+
+  return SWFMovie_add(mo, (SWFBlock)tf);
+}
+
+int
+main(int argc, char** argv)
+{
+  SWFMovie mo;
+  const char *srcdir=".";
+  char fdbfont[256];
+  SWFMovieClip  dejagnuclip;
+  
+  /*********************************************
+   *
+   * Initialization
+   *
+   *********************************************/
+
+  if ( argc>1 ) srcdir=argv[1];
+  else
+  {
+    fprintf(stderr, "Usage: %s <mediadir>\n", argv[0]);
+    return 1;
+  }
+
+  sprintf(fdbfont, "%s/Bitstream-Vera-Sans.fdb", srcdir);
+
+  puts("Setting things up");
+
+  Ming_init();
+  Ming_useSWFVersion (OUTPUT_VERSION);
+  //Ming_setScale(20.0); /* so we talk twips */
+ 
+  mo = newSWFMovie();
+  SWFMovie_setRate(mo, 1.0);
+  SWFMovie_setDimension(mo, 800, 600);
+  
+  dejagnuclip = get_dejagnu_clip((SWFBlock)get_default_font(srcdir), 10, 0, 0, 
800, 600);
+  SWFMovie_add(mo, (SWFBlock)dejagnuclip);
+  SWFMovie_nextFrame(mo); // 1st frame 
+
+
+  /*********************************************
+   *
+   * Add some textfields
+   *
+   *********************************************/
+  {
+    SWFDisplayItem it;
+    FILE *font_file = fopen(fdbfont, "r");
+    if ( font_file == NULL )
+    {
+      perror(fdbfont);
+      exit(1);
+    }
+    SWFBrowserFont bfont = newSWFBrowserFont("_sans");
+    SWFFont efont = loadSWFFontFromFile(font_file);
+
+    it = add_text_field(mo, efont, "First text");
+    SWFDisplayItem_setName(it, "dtext1");
+    SWFDisplayItem_moveTo(it, 0, 200);
+    it = add_text_field(mo, efont, "Zweites Textfeld");
+    SWFDisplayItem_setName(it, "etext1");
+    SWFDisplayItem_moveTo(it, 0, 300);
+
+    it = add_text_field(mo, efont, "Some more static text here... abcdefgh");
+    SWFDisplayItem_setName(it, "dtext2");
+    SWFDisplayItem_moveTo(it, 0, 400);
+  }
+  SWFMovie_nextFrame(mo); 
+
+  add_actions(mo, "createTextField('dynamictext1', 99, 10, 10, 10, 10);"
+                 "this.dynamictext1.text = 'Dynamic Text';");
+  
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  check(mo, "ts instanceof TextSnapshot");
+  check_equals(mo, "ts.getCount()", "64");
+
+  check_equals(mo, "ts.getText(0, 1)", "'F'");
+  check_equals(mo, "ts.getText(3, 3)", "'s'");
+  check_equals(mo, "ts.getText(-5, 5)", "'First'");
+  check_equals(mo, "ts.getText(10, 6)", "'Z'");
+  check_equals(mo, "ts.getText(0, 100)", "'First textZweites TextfeldSome more 
"
+                 "static text here... abcdefgh'");
+  add_actions(mo, "ss = ts.getText(100, 110);");
+  check_equals(mo, "typeof(ss)", "'string'");
+  check_equals(mo, "ss", "'h'");
+  check_equals(mo, "ss.length", "1");
+  
+  check_equals(mo, "ts.getText(0, 100, true)", 
+          "'First text\nZweites Textfeld\nSome more "
+                 "static text here... abcdefgh'");
+
+  add_actions(mo, "ts.setSelected(0, 30, true);");
+
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  check_equals(mo, "typeof(ts)", "'object'");
+  add_actions(mo, "backup = TextSnapshot;");
+  add_actions(mo, "TextSnapshot = undefined;");
+  add_actions(mo, "t = new TextSnapshot();");
+  check_equals(mo, "typeof(t)", "'undefined'");
+
+  check_equals(mo, "typeof(TextSnapshot)", "'undefined'");
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  xcheck_equals(mo, "typeof(ts)", "'undefined'");
+  add_actions(mo, "TextSnapshot = backup;");
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  check_equals(mo, "typeof(ts)", "'object'");
+  
+  add_actions(mo, "backup = TextSnapshot.prototype;");
+  add_actions(mo, "TextSnapshot.prototype = undefined;");
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  check_equals(mo, "typeof(ts)", "'object'");
+  add_actions(mo, "TextSnapshot.prototype = backup;");
+  add_actions(mo, "ts = this.getTextSnapshot();");
+  check_equals(mo, "typeof(ts)", "'object'");
+  
+  
+  add_actions(mo, "totals(); stop();");
+  
+
+
+  
+  SWFMovie_nextFrame(mo); 
+
+  /*****************************************************
+   *
+   * Output movie
+   *
+   *****************************************************/
+  puts("Saving " OUTPUT_FILENAME );
+
+  SWFMovie_save(mo, OUTPUT_FILENAME);
+
+  return 0;
+}


reply via email to

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