gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r10689: Implement TextSnapshot bette


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10689: Implement TextSnapshot better; all tests of implemented methods pass.
Date: Wed, 11 Mar 2009 14:41:02 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10689
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Wed 2009-03-11 14:41:02 +0100
message:
  Implement TextSnapshot better; all tests of implemented methods pass. 
  Selections are now queried directly from the StaticText characters.
  
  Derive two new classes from  generic_character (now DisplayObject) into
  Shape and StaticText so that they can more easily be used differently
  (for TextSnapshot). The inheritance of DisplayObject from character
  (should be: InteractiveObject) is still the wrong way round.
  
  Rename shape.h to Geometry.h to avoid any conflicts with Shape.h.
removed:
  libcore/generic_character.cpp
  libcore/generic_character.h
  libcore/shape.h
added:
  libcore/DisplayObject.cpp
  libcore/DisplayObject.h
  libcore/Geometry.h
  libcore/Shape.cpp
  libcore/Shape.h
  libcore/StaticText.cpp
  libcore/StaticText.h
modified:
  backend/PathParser.h
  backend/render_handler.h
  backend/render_handler_agg.cpp
  libcore/BitmapMovieInstance.cpp
  libcore/Button.cpp
  libcore/Makefile.am
  libcore/MovieClip.cpp
  libcore/MovieClip.h
  libcore/asobj/TextSnapshot_as.cpp
  libcore/asobj/TextSnapshot_as.h
  libcore/character.h
  libcore/parser/BitmapMovieDefinition.cpp
  libcore/parser/BitmapMovieDefinition.h
  libcore/parser/SWFMovieDefinition.h
  libcore/parser/character_def.cpp
  libcore/parser/character_def.h
  libcore/parser/shape_character_def.cpp
  libcore/parser/shape_character_def.h
  libcore/parser/sprite_definition.cpp
  libcore/parser/sprite_definition.h
  libcore/swf/DefineButtonTag.cpp
  libcore/swf/DefineButtonTag.h
  libcore/swf/DefineEditTextTag.cpp
  libcore/swf/DefineEditTextTag.h
  libcore/swf/DefineFontAlignZonesTag.cpp
  libcore/swf/DefineTextTag.cpp
  libcore/swf/DefineTextTag.h
  libcore/swf/DefineVideoStreamTag.cpp
  libcore/swf/DefineVideoStreamTag.h
  libcore/swf/TextRecord.cpp
  libcore/swf/TextRecord.h
  libcore/swf/tag_loaders.cpp
  testsuite/DummyMovieDefinition.h
  testsuite/libcore.all/EdgeTest.cpp
  testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10684.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Tue 2009-03-10 21:43:50 +0100
    message:
      Begin rearranging inheritance to reflect AS3 classes better; this makes
      handling StaticText objects easier for TextSnapshot, and also prepares
      for implementing AS3.
      
      generic_character becomes DisplayObject, from which Shape and StaticText
      inherit directly.
      
      character should derive from DisplayObject as InteractiveDisplayObject,
      not be its base class, but this is not yet implemented.
      
      All character_defs now require a createDisplayObject() method. This
      unfortunately includes BitmapMovieDefinition and SWFMovieDefinition, but
      that reflects the existing bad design.
    removed:
      libcore/generic_character.cpp
      libcore/generic_character.h
      libcore/shape.h
    added:
      libcore/DisplayObject.cpp
      libcore/DisplayObject.h
      libcore/Geometry.h
      libcore/Shape.cpp
      libcore/Shape.h
      libcore/StaticText.cpp
      libcore/StaticText.h
    modified:
      backend/render_handler.h
      backend/render_handler_agg.cpp
      libcore/BitmapMovieInstance.cpp
      libcore/Button.cpp
      libcore/Makefile.am
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      libcore/character.h
      libcore/parser/BitmapMovieDefinition.cpp
      libcore/parser/BitmapMovieDefinition.h
      libcore/parser/SWFMovieDefinition.h
      libcore/parser/character_def.cpp
      libcore/parser/character_def.h
      libcore/parser/shape_character_def.cpp
      libcore/parser/shape_character_def.h
      libcore/parser/sprite_definition.cpp
      libcore/parser/sprite_definition.h
      libcore/swf/DefineButtonTag.cpp
      libcore/swf/DefineButtonTag.h
      libcore/swf/DefineEditTextTag.cpp
      libcore/swf/DefineEditTextTag.h
      libcore/swf/DefineFontAlignZonesTag.cpp
      libcore/swf/DefineTextTag.cpp
      libcore/swf/DefineTextTag.h
      libcore/swf/DefineVideoStreamTag.cpp
      libcore/swf/DefineVideoStreamTag.h
      libcore/swf/tag_loaders.cpp
      testsuite/libcore.all/EdgeTest.cpp
    ------------------------------------------------------------
    revno: 10684.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Wed 2009-03-11 07:34:47 +0100
    message:
      Tidy up getStaticText so that it only returns StaticTexts, which disrupts 
the
      inheritance chain less.
      
      Clean up inheritance in the new classes: keep pointers to polymorphic
      classes as ungeneric as possible.
    modified:
      libcore/DisplayObject.cpp
      libcore/DisplayObject.h
      libcore/Shape.h
      libcore/StaticText.cpp
      libcore/StaticText.h
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      libcore/character.h
      libcore/parser/character_def.h
      testsuite/DummyMovieDefinition.h
    ------------------------------------------------------------
    revno: 10684.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Wed 2009-03-11 10:39:20 +0100
    message:
      Ugly version of working TextSnapshot (selection).
    modified:
      libcore/StaticText.cpp
      libcore/StaticText.h
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      libcore/swf/DefineTextTag.cpp
      libcore/swf/DefineTextTag.h
      libcore/swf/TextRecord.h
    ------------------------------------------------------------
    revno: 10684.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Wed 2009-03-11 11:14:31 +0100
    message:
      Clean up and document more.
    modified:
      libcore/DisplayObject.h
      libcore/StaticText.cpp
      libcore/StaticText.h
      libcore/asobj/TextSnapshot_as.cpp
      libcore/asobj/TextSnapshot_as.h
      libcore/character.h
    ------------------------------------------------------------
    revno: 10684.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Wed 2009-03-11 11:16:46 +0100
    message:
      Passing selection tests in TextSnapshotTest.
    modified:
      testsuite/misc-ming.all/TextSnapshotTest.c
    ------------------------------------------------------------
    revno: 10684.1.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Wed 2009-03-11 11:36:40 +0100
    message:
      Document StaticText.
      
      Drop unnecessary functor operator.
      
      Reduce debugging.
    modified:
      libcore/StaticText.h
      libcore/swf/TextRecord.cpp
      libcore/swf/TextRecord.h
=== modified file 'backend/PathParser.h'
--- a/backend/PathParser.h      2009-02-25 22:33:03 +0000
+++ b/backend/PathParser.h      2009-03-11 13:41:02 +0000
@@ -15,11 +15,11 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
-#ifndef __PATH_PARSER_H
-#define __PATH_PARSER_H
-
-
-#include "shape.h"
+#ifndef GNASH_PATH_PARSER_H
+#define GNASH_PATH_PARSER_H
+
+
+#include "Geometry.h"
 #include <vector>
 #include <deque>
 #include "cxform.h"

=== modified file 'backend/render_handler.h'
--- a/backend/render_handler.h  2009-01-22 20:10:39 +0000
+++ b/backend/render_handler.h  2009-03-10 20:43:50 +0000
@@ -147,7 +147,7 @@
 
 #include "gnash.h" // Quality
 #include "shape_character_def.h"    
-#include "generic_character.h"
+#include "DisplayObject.h"
 #include "Range2d.h"
 
 // Forward declarations.
@@ -159,7 +159,6 @@
     class cxform;
 
     class shape_character_def;
-    class generic_character;
 
     class GnashImage;
 }

=== modified file 'backend/render_handler_agg.cpp'
--- a/backend/render_handler_agg.cpp    2009-01-22 22:02:00 +0000
+++ b/backend/render_handler_agg.cpp    2009-03-10 20:43:50 +0000
@@ -126,7 +126,7 @@
 #include "Range2d.h"
 
 #include "shape_character_def.h" 
-#include "generic_character.h"
+#include "DisplayObject.h"
 
 #include <agg_rendering_buffer.h>
 #include <agg_renderer_base.h>

=== modified file 'libcore/BitmapMovieInstance.cpp'
--- a/libcore/BitmapMovieInstance.cpp   2009-02-25 22:33:03 +0000
+++ b/libcore/BitmapMovieInstance.cpp   2009-03-10 20:43:50 +0000
@@ -18,7 +18,7 @@
 #include "BitmapMovieInstance.h"
 #include "BitmapMovieDefinition.h"
 #include "fill_style.h"
-#include "shape.h" // for class path and class edge
+#include "Geometry.h" // for class path and class edge
 #include "render.h" // for ::display
 
 namespace gnash {
@@ -34,7 +34,7 @@
        character_def* chdef = def->get_character_def(1); 
        assert(chdef);
        boost::intrusive_ptr<character> ch = 
-        chdef->create_character_instance(this, 1);
+        chdef->createDisplayObject(this, 1);
        
        const int depth = 1 + character::staticDepthOffset;
        place_character(ch.get(), depth);

=== modified file 'libcore/Button.cpp'
--- a/libcore/Button.cpp        2009-01-22 20:10:39 +0000
+++ b/libcore/Button.cpp        2009-03-10 20:43:50 +0000
@@ -741,7 +741,7 @@
                     character::staticDepthOffset + 1;
                 int ch_id = bdef.m_character_id;
 
-                character* ch = 
bdef.m_character_def->create_character_instance(
+                character* ch = bdef.m_character_def->createDisplayObject(
                         this, ch_id);
                 ch->setMatrix(mat, true); // update caches
                 ch->set_cxform(cx); 
@@ -904,7 +904,7 @@
         int ch_id = bdef.m_character_id;
 
         character* ch =
-            bdef.m_character_def->create_character_instance(this, ch_id);
+            bdef.m_character_def->createDisplayObject(this, ch_id);
         ch->setMatrix(mat, true);  // update caches
     
         // TODO: who cares about color, depth etc.
@@ -937,7 +937,7 @@
         int ch_depth = bdef.m_button_layer+character::staticDepthOffset+1;
         int ch_id = bdef.m_character_id;
 
-        character* ch = bdef.m_character_def->create_character_instance(
+        character* ch = bdef.m_character_def->createDisplayObject(
                 this, ch_id);
         ch->setMatrix(mat, true);  // update caches
         ch->set_cxform(cx); 

=== added file 'libcore/DisplayObject.cpp'
--- a/libcore/DisplayObject.cpp 1970-01-01 00:00:00 +0000
+++ b/libcore/DisplayObject.cpp 2009-03-11 06:34:47 +0000
@@ -0,0 +1,56 @@
+// DisplayObject.cpp:  Mouse/Character handling, 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
+//
+
+#include "DisplayObject.h"
+
+namespace gnash
+{
+
+void
+DisplayObject::add_invalidated_bounds(InvalidatedRanges& ranges,
+        bool force)
+{
+    ranges.add(m_old_invalidated_ranges);
+    if (isVisible() && (m_invalidated||force))
+    {
+        rect bounds;        
+        bounds.expand_to_transformed_rect(getWorldMatrix(),
+                        getDefinition()->get_bound());
+
+        ranges.add(bounds.getRange());                        
+    }        
+}
+
+
+bool
+DisplayObject::pointInShape(boost::int32_t  x, boost::int32_t  y) const
+{
+    SWFMatrix wm = getWorldMatrix();
+    SWFMatrix wm_inverse = wm.invert();
+    point lp(x, y);
+    wm_inverse.transform(lp);
+    return getDefinition()->point_test_local(lp.x, lp.y, wm);
+}
+
+} // namespace gnash
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== added file 'libcore/DisplayObject.h'
--- a/libcore/DisplayObject.h   1970-01-01 00:00:00 +0000
+++ b/libcore/DisplayObject.h   2009-03-11 10:14:31 +0000
@@ -0,0 +1,126 @@
+// 
+//   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_DISPLAY_OBJECT_H
+#define GNASH_DISPLAY_OBJECT_H
+
+#include "smart_ptr.h" // GNASH_USE_GC
+#include "character.h" // for inheritance
+#include "character_def.h"
+
+#include <cassert>
+
+namespace gnash {
+    class character_def;
+    class StaticText;
+    namespace SWF {
+        class TextRecord;
+    }
+}
+
+namespace gnash {
+
+/// The base class for all rendered objects on the Stage.
+//
+/// Objects of type DisplayObject are non-interactive.
+class DisplayObject : public character
+{
+
+public:
+
+       DisplayObject(character* parent, int id)
+               :
+               character(parent, id)
+       {
+       }
+
+    virtual ~DisplayObject() {}
+
+    /// Render the DisplayObject.
+    //
+    /// All DisplayObjects must have a display() function.
+       virtual void display() = 0;
+
+    /// Whether the DisplayObject can handle a mouse event.
+    //
+    /// Normal DisplayObjects apparently cannot handle
+    /// mouse events.
+    /// @return     true if the DisplayObject can handle mouse
+    ///             events
+       virtual bool can_handle_mouse_event() const
+    {
+               return false;
+       }
+
+    /// Search for StaticText objects
+    //
+    /// If this is a StaticText object and contains SWF::TextRecords, these
+    /// are written to the passed parameter.
+    /// @ return    0 if this object is not a StaticText or contains no text.
+    virtual StaticText* getStaticText(std::vector<const SWF::TextRecord*>&,
+            size_t&)
+    {
+        return 0;
+    }
+
+       rect getBounds() const
+    {
+               return getDefinition()->get_bound();
+       }
+
+       /// Generic character is NEVER a mouse entity by default, so
+       /// the default implementation of this method always returns NULL.
+       /// Override it from subclasses that do can be mouse entities.
+       ///
+       /// If you need to check for a generic character to contain a 
+       /// given point, use the pointInShape() function instead.
+       /// 
+       virtual character* get_topmost_mouse_entity(boost::int32_t /*x*/, 
+            boost::int32_t /*y*/)
+       {
+               return 0;
+       }
+
+       // See dox in character.h
+       virtual bool pointInShape(boost::int32_t  x, boost::int32_t  y) const;
+
+       void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
+
+protected:
+
+    /// Retrieve the immutable definition of this DisplayObject.
+    //
+    /// All subclasses must override this, but may return 0. In
+    /// this case, they must also override any functions that
+    /// call getDefinition().
+    /// @ return    The immutable character_def of this DisplayObject
+    ///             or 0 if none exists.
+    virtual character_def* getDefinition() const = 0;
+
+};
+
+
+} // namespace gnash
+
+
+#endif 
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== added file 'libcore/Geometry.h'
--- a/libcore/Geometry.h        1970-01-01 00:00:00 +0000
+++ b/libcore/Geometry.h        2009-03-10 20:43:50 +0000
@@ -0,0 +1,594 @@
+//   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_GEOMETRY_H
+#define GNASH_GEOMETRY_H
+
+#include "dsodefs.h"
+#include "SWFMatrix.h" 
+
+#include <vector> // for path composition
+#include <cmath> // sqrt
+
+
+// Forward declarations
+namespace gnash {
+  class rect; 
+}
+
+namespace gnash { 
+
+  /// \brief
+  /// Defines an edge with a control point and an anchor point.
+  /// 
+  /// Could be a quadratic bezier curve, or a straight line(degenerated curve).
+  ///
+  class Edge
+  {
+  public:
+       
+    // Quadratic bezier: point = p0 * t^2 + p1 * 2t(1-t) + p2 * (1-t)^2
+    point cp; // control point, TWIPS
+    point ap; // anchor  point, TWIPS
+
+    Edge() 
+        :
+    cp(0, 0), ap(0, 0)
+    {  };
+    
+    Edge(boost::int32_t cx, boost::int32_t cy, boost::int32_t ax, 
boost::int32_t ay)
+      :
+      cp(cx, cy), ap(ax, ay)
+    {  }
+
+    Edge(const Edge& from)
+      : 
+      cp(from.cp), ap(from.ap)
+    {  }
+
+    Edge(const point& ncp, const point& nap)
+      :
+      cp(ncp), ap(nap)
+    {  }
+
+    bool isStraight() const
+    {
+        return cp == ap;
+    }
+
+    // TODO: drop this!
+    bool is_straight() const { return isStraight(); }
+    
+    /// Transform the edge according to the given SWFMatrix.
+    void  transform(const SWFMatrix& mat)
+    {
+        mat.transform(ap);
+        mat.transform(cp);
+    }
+
+    /// Return squared distance between point pt and segment A-B
+    static double
+    squareDistancePtSeg(const point& p, const point& A, const point& B)
+    {
+        boost::int32_t dx = B.x - A.x;
+        boost::int32_t dy = B.y - A.y;
+
+        if ( dx == 0 && dy == 0 ) 
+        {
+            return p.squareDistance(A);
+        }
+
+        boost::int32_t pdx = p.x - A.x;
+        boost::int32_t pdy = p.y - A.y;
+
+        double u = ( (double)(pdx) * dx + (double)(pdy) * dy ) / ( 
(double)(dx)*dx + (double)(dy)*dy );
+
+        if (u <= 0)
+        {
+            return p.squareDistance(A); 
+        }
+
+        if (u >= 1)
+        {
+            return p.squareDistance(B);
+        }
+
+        point px(A, B, u); // FIXME: this interpolation introduce a precision 
loss (point is int-based)
+        return p.squareDistance(px);
+    }
+
+    /// Return distance between point pt and segment A-B
+    static double
+    distancePtSeg(const point& pt, const point& A, const point& B)
+    {
+        double square = squareDistancePtSeg(pt, A, B);
+        return std::sqrt(square);
+    }
+
+    /// Find point of the quadratic curve defined by points A,C,B
+    //
+    /// @param A The first point
+    /// @param C The second point (control point)
+    /// @param B The third point (anchor point)
+    /// @param ret The point to write result into
+    /// @param t the step factor between 0 and 1
+    ///
+
+    static point
+    pointOnCurve(const point& A, 
+        const point& C, 
+        const point& B, float t)
+    {
+        point Q1(A, C, t);
+        point Q2(C, B, t);
+        point R(Q1, Q2, t);
+
+        return R;
+    }
+
+    /// Return square distance between point pt and the point on curve found by
+    /// applying the T parameter to the quadratic bezier curve function
+    //
+    /// @param A The first point of the bezier curve
+    /// @param C The second point of the bezier curve (control point)
+    /// @param B The third point of the bezier curve (anchor point)
+    /// @param p The point we want to compute distance from 
+    /// @param t the step factor between 0 and 1
+    ///
+    static boost::int64_t squareDistancePtCurve(const point& A,
+               const point& C,
+               const point& B,
+               const point& p, float t)
+    {
+      return p.squareDistance( pointOnCurve(A, C, B, t) );
+    }
+  };
+
+
+  ///\brief
+  /// A subset of a shape, a series of edges sharing a single set of styles. 
+  class DSOEXPORT Path
+  {
+  public:
+    /// Left fill style index (1-based)
+    unsigned m_fill0;
+
+    /// Right fill style index (1-based)
+    unsigned m_fill1;
+
+    /// Line style index (1-based)
+    unsigned m_line;
+
+    /// Start point of the path
+    point ap; 
+
+    /// Edges forming the path
+    std::vector<Edge> m_edges;
+
+    /// This flag is set when the path is the first one of a new "sub-shape".
+    /// All paths with a higher index in the list belong to the same 
+    /// shape unless they have m_new_shape==true on their own.
+    /// Sub-shapes affect the order in which outlines and shapes are rendered.
+    bool m_new_shape;
+    
+    /// Default constructor
+    //
+    /// @param newShape
+    ///  True if this path starts a new subshape
+    ///
+    Path(bool newShape = false)
+      : 
+    m_new_shape(newShape)
+    {
+      reset(0, 0, 0, 0, 0);
+    }
+
+    Path(const Path& from)
+      : 
+      m_fill0(from.m_fill0),
+      m_fill1(from.m_fill1),
+      m_line(from.m_line),
+      ap(from.ap),
+      m_edges(from.m_edges),
+      m_new_shape(from.m_new_shape)        
+    {
+    }
+    
+    /// Initialize a path 
+    //
+    /// @param ax
+    ///  X coordinate of path origin in TWIPS
+    ///
+    /// @param ay
+    ///  Y coordinate in path origin in TWIPS
+    ///
+    /// @param fill0
+    ///  Fill style index for left fill (1-based).
+    ///  Zero means NO style.
+    ///
+    /// @param fill1
+    ///  Fill style index for right fill (1-based)
+    ///  Zero means NO style.
+    ///
+    /// @param line
+    ///  Line style index for right fill (1-based).
+    ///  Zero means NO style.
+    ///
+    /// @param newShape
+    ///  True if this path starts a new subshape
+    Path(boost::int32_t ax, boost::int32_t ay, 
+        unsigned fill0, unsigned fill1, unsigned line, 
+        bool newShape)
+      :
+      m_new_shape(newShape)
+    {
+        reset(ax, ay, fill0, fill1, line);
+    }
+
+    /// Re-initialize a path, maintaining the "new shape" flag untouched
+    //
+    /// @param ax
+    ///  X coordinate of path origin in TWIPS
+    ///
+    /// @param ay
+    ///  Y coordinate in path origin in TWIPS
+    ///
+    /// @param fill0
+    ///  Fill style index for left fill
+    ///
+    /// @param fill1
+    ///  Fill style index for right fill
+    //
+    /// @param line
+    ///  Line style index for right fill
+    ///
+    void  reset(boost::int32_t ax, boost::int32_t ay, 
+        unsigned fill0, unsigned fill1, unsigned line)
+    // Reset all our members to the given values, and clear our edge list.
+    {
+        ap.x = ax;
+        ap.y = ay;
+        m_fill0 = fill0;
+        m_fill1 = fill1;
+        m_line = line;
+
+        m_edges.resize(0);
+        assert(is_empty());
+    }
+
+    /// Return true if we have no edges.
+    bool  is_empty() const
+    {
+        return m_edges.empty();
+    }
+
+    /// Expand given rect to include bounds of this path
+    //
+    /// @param r
+    ///  The rectangle to expand with our own bounds
+    ///
+    /// @param thickness
+    ///  The thickess of our lines, half the thickness will
+    ///  be added in all directions in swf8+, all of it will
+    ///  in swf7-
+    ///
+    /// @param swfVersion
+    ///  SWF version to use.
+    ///
+    void
+    expandBounds(rect& r, unsigned int thickness, int swfVersion) const
+    {
+        const Path&  p = *this;
+        size_t nedges = m_edges.size();
+        
+        if ( ! nedges ) return; // this path adds nothing
+
+        if (thickness)
+        {
+            // NOTE: Half of thickness would be enough (and correct) for
+            // radius, but that would not match how Flash calculates the
+            // bounds using the drawing API.                        
+            unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
+
+            r.expand_to_circle(ap.x, ap.y, radius);
+            for (unsigned int j = 0; j<nedges; j++)
+            {
+                r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
+                r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
+            }
+        }
+        else
+        {
+            r.expand_to_point(ap.x, ap.y);
+            for (unsigned int j = 0; j<nedges; j++)
+            {
+                r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
+                r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
+            }
+        }
+    }
+
+    /// @{ Primitives for the Drawing API
+    ///
+    /// Name of these functions track Ming interface
+    ///
+
+    /// Draw a straight line.
+    //
+    /// Point coordinates are relative to path origin
+    /// and expressed in TWIPS.
+    ///
+    /// @param x
+    ///  X coordinate in TWIPS
+    ///
+    /// @param y
+    ///  Y coordinate in TWIPS
+    ///
+    void 
+    drawLineTo(boost::int32_t dx, boost::int32_t dy)
+    {
+        m_edges.push_back(Edge(dx, dy, dx, dy)); 
+    }
+
+    /// Draw a curve.
+    //
+    /// Offset values are relative to path origin and
+    /// expressed in TWIPS.
+    ///
+    /// @param cx
+    ///  Control point's X coordinate.
+    ///
+    /// @param cy
+    ///  Control point's Y coordinate.
+    ///
+    /// @param ax
+    ///  Anchor point's X ordinate.
+    ///
+    /// @param ay
+    ///  Anchor point's Y ordinate.
+    ///
+    void 
+    drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, 
boost::int32_t ady)
+    {
+        m_edges.push_back(Edge(cdx, cdy, adx, ady)); 
+    }
+
+    /// Remove all edges and reset style infomation 
+    void clear()
+    {
+        m_edges.resize(0);
+        m_fill0 = m_fill1 = m_line = 0;
+    }
+
+    /// @} Primitives for the Drawing API
+
+
+    /// Returns true if the last and the first point of the path match
+    bool  isClosed() const 
+    {
+        if ( m_edges.empty() ) 
+        {
+            return true;  
+        }
+        else
+        {
+            return m_edges.back().ap == ap; 
+        }
+    }
+
+    /// Close this path with a straight line, if not already closed
+    void  close()
+    {
+        if ( m_edges.empty() ) return;
+
+        // Close it with a straight edge if needed
+        const Edge& lastedge = m_edges.back();
+        if ( lastedge.ap != ap )
+        {
+            Edge newedge(ap, ap);
+            m_edges.push_back(newedge);
+        }
+    }
+
+    /// \brief
+    /// Return true if the given point is within the given squared distance
+    /// from this path edges.
+    //
+    /// NOTE: if the path is empty, false is returned.
+    ///
+    bool
+    withinSquareDistance(const point& p, double dist) const
+    {
+      size_t nedges = m_edges.size();
+
+      if ( ! nedges ) return false;
+
+      point px(ap);
+      for (size_t i=0; i<nedges; ++i)
+      {
+        const Edge& e = m_edges[i];
+        point np(e.ap);
+
+        if ( e.isStraight() )
+        {
+          double d = Edge::squareDistancePtSeg(p, px, np);
+
+          if ( d <= dist ) return true;
+        }
+        else
+        {
+
+          const point& A = px;
+          const point& C = e.cp;
+          const point& B = e.ap;
+
+          // Approximate the curve to segCount segments
+          // and compute distance of query point from each
+          // segment.
+          //
+          // TODO: find an apprpriate value for segCount based
+          //       on rendering scale ?
+          //
+          int segCount = 10; 
+          point p0(A.x, A.y);
+          for (int i=1; i<=segCount; ++i)
+          {
+            float t1 = (float)(i) / segCount;
+            point p1 = Edge::pointOnCurve(A, C, B, t1);
+
+            // distance from point and segment being an approximation 
+            // of the curve 
+            double d = Edge::squareDistancePtSeg(p, p0, p1);
+            if ( d <= dist ) return true;
+
+            p0.setTo(p1.x, p1.y);
+          }
+        }
+        px = np;
+      }
+
+      return false;
+    }
+
+    /// Transform all path coordinates according to the given SWFMatrix.
+    void  transform(const SWFMatrix& mat)
+    {
+               mat.transform(ap);
+               std::vector<Edge>::iterator it = m_edges.begin(), ie = 
m_edges.end();
+               for(; it != ie; it++)
+               {
+                       (*it).transform(mat);
+               }
+    }    
+
+    /// Set this path as the start of a new (sub)shape
+    void  setNewShape() 
+    { 
+        m_new_shape=true; 
+    }
+
+    /// Return true if this path starts a new (sub)shape
+    bool  getNewShape() const 
+    { 
+        return m_new_shape; 
+    }
+
+    /// Return true if this path contains no edges
+    bool  empty() const
+    {
+        return is_empty();
+    }
+
+    /// Set the fill to use on the left side
+    //
+    /// @param f
+    ///  The fill index (1-based).
+    ///  When this path is added to a shape_character_def,
+    ///  the index (decremented by 1) will reference an element
+    ///  in the fill_style vector defined for that shape.
+    ///  If zero, no fill will be active.
+    ///
+    void setLeftFill(unsigned f)
+    {
+        m_fill0 = f;
+    }
+
+    unsigned getLeftFill() const
+    {
+        return m_fill0;
+    }
+
+    /// Set the fill to use on the left side
+    //
+    /// @param f
+    ///  The fill index (1-based).
+    ///  When this path is added to a shape_character_def,
+    ///  the index (decremented by 1) will reference an element
+    ///  in the fill_style vector defined for that shape.
+    ///  If zero, no fill will be active.
+    ///
+    void setRightFill(unsigned f)
+    {
+        m_fill1 = f;
+    }
+
+    unsigned getRightFill() const
+    {
+        return m_fill1;
+    }
+
+    /// Set the line style to use for this path
+    //
+    /// @param f
+    ///  The line_style index (1-based).
+    ///  When this path is added to a shape_character_def,
+    ///  the index (decremented by 1) will reference an element
+    ///  in the line_style vector defined for that shape.
+    ///  If zero, no fill will be active.
+    ///
+    void setLineStyle(unsigned i)
+    {
+        m_line = i;
+    }
+
+    unsigned getLineStyle() const
+    {
+        return m_line;
+    }
+
+    /// Return the number of edges in this path
+    size_t size() const
+    {
+        return m_edges.size();
+    }
+
+    /// Return a reference to the Nth edge 
+    Edge& operator[] (size_t n)
+    {
+        return m_edges[n];
+    }
+
+    /// Return a const reference to the Nth edge 
+    const Edge& operator[] (size_t n) const
+    {
+        return m_edges[n];
+    }
+
+    /// Returns true if this path begins a new subshape. <-- VERIFYME
+    bool isNewShape() const
+    {
+        return m_new_shape;
+    }
+ 
+  }; // end of class Path
+
+
+  typedef Edge  edge;
+  typedef Path  path;
+
+}  // end namespace gnash
+
+#endif // GNASH_SHAPE_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am       2009-02-27 06:46:40 +0000
+++ b/libcore/Makefile.am       2009-03-10 20:43:50 +0000
@@ -63,6 +63,8 @@
        cxform.cpp \
        DynamicShape.cpp        \
        Bitmap.cpp \
+       Shape.cpp \
+       StaticText.cpp \
        TextField.cpp \
         BlurFilter.cpp \
         GlowFilter.cpp \
@@ -73,7 +75,7 @@
         BevelFilter.cpp \
         GradientBevelFilter.cpp \
         parser/filter_factory.cpp \
-       generic_character.cpp \
+       DisplayObject.cpp \
        SWFMatrix.cpp \
        movie_instance.cpp \
        movie_root.cpp \
@@ -161,7 +163,9 @@
         parser/filter_factory.h \
        Font.h \
        fontlib.h \
-       generic_character.h \
+       Shape.h \
+       StaticText.h \
+       DisplayObject.h \
        gnash.h \
        GnashKey.h \
        impl.h \
@@ -174,7 +178,7 @@
        rect.h \
        render.h \
        ExportableResource.h \
-       shape.h \
+       Geometry.h      \
        MovieClip.h \
        SWFStream.h \
        styles.h \

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2009-03-10 06:23:07 +0000
+++ b/libcore/MovieClip.cpp     2009-03-10 20:43:50 +0000
@@ -482,7 +482,7 @@
     character(parent, id),
     m_root(r),
     _drawable(new DynamicShape()),
-    _drawable_inst(_drawable->create_character_instance(this, 0)),
+    _drawable_inst(_drawable->createDisplayObject(this, 0)),
     m_play_state(PLAY),
     m_current_frame(0),
     m_has_looped(false),
@@ -1528,7 +1528,7 @@
     if (existing_char) return NULL;
 
     boost::intrusive_ptr<character> ch =
-        cdef->create_character_instance(this, tag->getID());
+        cdef->createDisplayObject(this, tag->getID());
 
     if (tag->hasName()) ch->set_name(tag->getName());
     else if (ch->wantsInstanceName())
@@ -1600,7 +1600,7 @@
         else
         {
             boost::intrusive_ptr<character> ch = 
-                cdef->create_character_instance(this, tag->getID());
+                cdef->createDisplayObject(this, tag->getID());
 
             // TODO: check if we can drop this for REPLACE!
             // should we rename the character when it's REPLACE tag?
@@ -3220,7 +3220,7 @@
     boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
 
     boost::intrusive_ptr<character> newch =
-        exported_movie->create_character_instance(movieclip.get(), 0);
+        exported_movie->createDisplayObject(movieclip.get(), 0);
 
 #ifndef GNASH_USE_GC
     assert(newch->get_ref_count() > 0);

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2009-03-05 14:03:05 +0000
+++ b/libcore/MovieClip.h       2009-03-10 20:43:50 +0000
@@ -102,8 +102,8 @@
     ///     to be deprecated if every instance has a reference to its
     ///     definition, which should know its id...
     ///
-    MovieClip(movie_definition* def,
-        movie_instance* root, character* parent, int id);
+    MovieClip(movie_definition* def, movie_instance* root,
+            character* parent, int id);
 
     virtual ~MovieClip();
 

=== added file 'libcore/Shape.cpp'
--- a/libcore/Shape.cpp 1970-01-01 00:00:00 +0000
+++ b/libcore/Shape.cpp 2009-03-10 20:43:50 +0000
@@ -0,0 +1,37 @@
+// Shape.cpp:  Mouse/Character handling, 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
+//
+
+#include "Shape.h"
+
+namespace gnash
+{
+
+void  
+Shape::display()
+{
+    _def->display(this); // pass in transform info
+    clear_invalidated();
+}
+
+} // namespace gnash
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== added file 'libcore/Shape.h'
--- a/libcore/Shape.h   1970-01-01 00:00:00 +0000
+++ b/libcore/Shape.h   2009-03-11 06:34:47 +0000
@@ -0,0 +1,82 @@
+// 
+//   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_SHAPE_H
+#define GNASH_SHAPE_H
+
+#include "smart_ptr.h" // GNASH_USE_GC
+#include "DisplayObject.h"
+#include "shape_character_def.h"
+#include <cassert>
+
+// Forward declarations
+namespace gnash {
+    class character_def;
+}
+
+namespace gnash {
+
+/// For characters that don't store unusual state in their instances.
+class Shape : public DisplayObject
+{
+
+public:
+
+       Shape(shape_character_def* def, character* parent, int id)
+               :
+               DisplayObject(parent, id),
+               _def(def)
+       {
+           assert(_def);
+       }
+
+       virtual void display();
+
+protected:
+
+    character_def* getDefinition() const
+    {
+        return _def.get();
+    }
+
+#ifdef GNASH_USE_GC
+       /// Mark reachable resources (for the GC)
+       void markReachableResources() const
+       {
+               assert(isReachable());
+        _def->setReachable();
+               markCharacterReachable();
+       }
+#endif
+
+private:
+       
+    const boost::intrusive_ptr<shape_character_def> _def;
+
+};
+
+
+} // namespace gnash
+
+
+#endif 
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== added file 'libcore/StaticText.cpp'
--- a/libcore/StaticText.cpp    1970-01-01 00:00:00 +0000
+++ b/libcore/StaticText.cpp    2009-03-11 10:14:31 +0000
@@ -0,0 +1,53 @@
+// Shape.cpp:  Mouse/Character handling, 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
+//
+
+#include "StaticText.h"
+#include "swf/DefineTextTag.h"
+
+namespace gnash
+{
+
+StaticText*
+StaticText::getStaticText(std::vector<const SWF::TextRecord*>& to,
+        size_t& numChars)
+{
+    _selectedText.clear();
+
+    if (_def->extractStaticText(to, numChars)) {
+        _selectedText.resize(numChars);
+        return this;
+    }
+    
+    return 0;
+}
+
+
+void  
+StaticText::display()
+{
+    _def->display(this); // pass in transform info
+    clear_invalidated();
+}
+
+} // namespace gnash
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== added file 'libcore/StaticText.h'
--- a/libcore/StaticText.h      1970-01-01 00:00:00 +0000
+++ b/libcore/StaticText.h      2009-03-11 10:36:40 +0000
@@ -0,0 +1,130 @@
+// 
+//   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_STATIC_TEXT_H
+#define GNASH_STATIC_TEXT_H
+
+#include "smart_ptr.h" // GNASH_USE_GC
+#include "character.h" // for inheritance
+#include "DisplayObject.h"
+#include "swf/DefineTextTag.h"
+
+#include <boost/dynamic_bitset.hpp>
+#include <cassert>
+
+// Forward declarations
+namespace gnash {
+    class character_def;
+    namespace SWF {
+        class TextRecord;
+    }
+}
+
+namespace gnash {
+
+/// Static text fields, SWF-defined with read-only text.
+//
+/// StaticText objects hold mutable selection and color information.
+class StaticText : public DisplayObject
+{
+public:
+
+       StaticText(SWF::DefineTextTag* def, character* parent, int id)
+               :
+        DisplayObject(parent, id),
+        _def(def)
+       {
+        assert(_def);
+       }
+
+    /// Return a pointer to this if our definition contains any static text.
+    //
+    /// This is non-const because a TextSnapshot needs to add selection and
+    /// color information to this StaticText. It also resets selection.
+    //
+    /// @param to       A vector of pointers to TextRecords containing text.
+    /// @param numChars The total number of characters in all TextRecords is
+    ///                 written to this variable.
+    /// Note: This function always removes any existing selection and resizes
+    /// the bitset to the number of characters in all TextRecords.
+    virtual StaticText* getStaticText(std::vector<const SWF::TextRecord*>& to,
+            size_t& numChars);
+
+       virtual void display();
+
+    void setSelected(size_t pos, bool selected) {
+        _selectedText.set(pos, selected);
+    }
+
+    /// Return a bitset showing which characters (by index) are selected.
+    //
+    /// Note: mutable information is meaningless until the StaticText is
+    /// queried with getStaticText(). This is because under normal
+    /// circumstances there is no need for it.
+    /// Note also: the size() member of boost::dynamic_bitset returns 0 before
+    /// getStaticText() is called; afterwards it is equivalent to the
+    /// number of characters in the StaticText's definition.
+    const boost::dynamic_bitset<>& getSelected() const {
+        return _selectedText;
+    }
+
+    void setSelectionColor(boost::uint32_t color);
+
+protected:
+
+    character_def* getDefinition() const {
+        return _def.get();
+    }
+
+#ifdef GNASH_USE_GC
+       /// Mark reachable resources (for the GC)
+       void markReachableResources() const
+       {
+               assert(isReachable());
+        _def->setReachable();
+               markCharacterReachable();
+       }
+#endif
+
+private:
+
+    const boost::intrusive_ptr<SWF::DefineTextTag> _def;
+
+    /// A bitmask indicating which static text characters are selected
+    //
+    /// This is only present for static text fields, and only after
+    /// a TextSnapshot has queried the character for text.
+    boost::dynamic_bitset<> _selectedText;
+
+    /// The color of the background for selected characters.
+    //
+    /// This is alawys opaque.
+    rgba _selectionColor;
+
+};
+
+
+}      // end namespace gnash
+
+
+#endif // GNASH_GENERIC_CHARACTER_H
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

=== modified file 'libcore/asobj/TextSnapshot_as.cpp'
--- a/libcore/asobj/TextSnapshot_as.cpp 2009-03-10 12:22:29 +0000
+++ b/libcore/asobj/TextSnapshot_as.cpp 2009-03-11 10:14:31 +0000
@@ -28,7 +28,7 @@
 #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 "StaticText.h"
 #include "DisplayList.h"
 #include "MovieClip.h"
 #include "Font.h"
@@ -39,7 +39,6 @@
 #include <boost/algorithm/string/compare.hpp>
 #include <boost/dynamic_bitset.hpp>
 #include <algorithm>
-#include <numeric>
 
 namespace gnash {
 
@@ -69,16 +68,6 @@
 
 namespace {
 
-/// Accumulate the number of glyphs in a TextRecord.
-struct CountRecords
-{
-    size_t operator()(size_t c, const TextSnapshot_as::Records::value_type t) {
-        const SWF::TextRecord::Glyphs& glyphs = t->glyphs();
-        size_t ret = c + glyphs.size();
-        return ret;
-    }
-};
-
 /// Locate static text in a character.
 //
 /// Static text (TextRecords) are added to a vector, which should 
@@ -94,15 +83,17 @@
     {}
 
     void operator()(character* ch) {
+
+        /// This is not tested.
         if (ch->isUnloaded()) return;
 
         TextSnapshot_as::Records text;
-        generic_character* tf;
+        StaticText* tf;
+        size_t numChars;
 
-        if ((tf = ch->getStaticText(text))) {
+        if ((tf = ch->getStaticText(text, numChars))) {
             _fields.push_back(std::make_pair(tf, text));
-            _count = std::accumulate(text.begin(), text.end(), _count,
-                    CountRecords());
+            _count += numChars;
         }
     }
 
@@ -122,31 +113,71 @@
     as_object(getTextSnapshotInterface()),
     _textFields(),
     _valid(mc),
-    _count(getTextFields(mc, _textFields)),
-    _selected(_count)
+    _count(getTextFields(mc, _textFields))
 {
 }
 
 void
 TextSnapshot_as::setSelected(size_t start, size_t end, bool selected)
 {
-    start = std::min(start, _selected.size());
-    end = std::min(end, _selected.size());
+    /// If there are no TextFields, there is nothing to do.
+    if (_textFields.empty()) return;
+
+    start = std::min(start, _count);
+    end = std::min(end, _count);
+
+    TextFields::const_iterator field = _textFields.begin();
+
+    size_t totalChars = field->first->getSelected().size();
+    size_t fieldStartIndex = 0;
 
     for (size_t i = start; i < end; ++i) {
-        _selected.set(i, selected);
+
+        /// Find the field containing the start index.
+        while (totalChars <= i) {
+            fieldStartIndex = totalChars;
+            ++field;
+
+            if (field == _textFields.end()) return;
+            
+            const boost::dynamic_bitset<>& sel = field->first->getSelected();
+            totalChars += sel.size();
+            continue;
+        }
+        field->first->setSelected(i - fieldStartIndex, selected);
     }
 }
 
 bool
 TextSnapshot_as::getSelected(size_t start, size_t end) const
 {
-    start = std::min(start, _selected.size());
-    end = std::min(end, _selected.size());
+
+    if (_textFields.empty()) return false;
+
+    start = std::min(start, _count);
+    end = std::min(end, _count);
+
+    TextFields::const_iterator field = _textFields.begin();
+
+    size_t totalChars = field->first->getSelected().size();
+    size_t fieldStartIndex = 0;
 
     for (size_t i = start; i < end; ++i) {
-        if (_selected.test(i)) return true;
+
+        /// Find the field containing the start index.
+        while (totalChars <= i) {
+            fieldStartIndex = totalChars;
+            ++field;
+            if (field == _textFields.end()) return false;
+
+            const boost::dynamic_bitset<>& sel = field->first->getSelected();
+            totalChars += sel.size();
+            continue;
+        }
+
+        if (field->first->getSelected().test(i - fieldStartIndex)) return true;
     }
+    
     return false;
 }
 
@@ -168,6 +199,9 @@
 
         const Records& rec = field->second;
         const SWFMatrix& mat = field->first->getMatrix();
+        const boost::dynamic_bitset<>& selected = field->first->getSelected();
+
+        const std::string::size_type fieldStartIndex = pos;
 
         for (Records::const_iterator j = rec.begin(), end = rec.end();
                 j != end; ++j) {
@@ -199,7 +233,8 @@
                 as_object* el = new as_object;
 
                 el->init_member("indexInRun", pos);
-                el->init_member("selected", _selected.test(pos));
+                el->init_member("selected",
+                        selected.test(pos - fieldStartIndex));
                 el->init_member("font", font->name());
                 el->init_member("color", tr->color().toRGBA());
                 el->init_member("height", TWIPS_TO_PIXELS(tr->textHeight()));
@@ -227,7 +262,7 @@
 }
 
 void
-TextSnapshot_as::makeString(std::string& to, bool newline,
+TextSnapshot_as::makeString(std::string& to, bool newline, bool selectedOnly,
         std::string::size_type start, std::string::size_type len) const
 {
 
@@ -241,6 +276,10 @@
         if (newline && pos > start) to += '\n';
 
         const Records& records = field->second;
+        const boost::dynamic_bitset<>& selected = field->first->getSelected();
+
+        /// Remember the position at the beginning of the StaticText.
+        const std::string::size_type fieldStartIndex = pos;
 
         for (Records::const_iterator j = records.begin(), end = records.end();
                 j != end; ++j) {
@@ -267,7 +306,9 @@
                     continue;
                 }
                 
-                to += font->codeTableLookup(k->index, true);
+                if (!selectedOnly || selected.test(pos - fieldStartIndex)) {
+                    to += font->codeTableLookup(k->index, true);
+                }
                 ++pos;
                 if (pos - start == len) return;
             }
@@ -289,7 +330,7 @@
     end = std::max(start + 1, end);
 
     std::string snapshot;
-    makeString(snapshot, nl, start, end - start);
+    makeString(snapshot, nl, false, start, end - start);
 
     return snapshot;
 
@@ -300,15 +341,7 @@
 {
     std::string sel;
     
-    for (size_t i = 0, e = _selected.size(); i != e; ++i) {
-        while (!_selected.test(i)) {
-            ++i;
-            if (i == e) return sel;
-        }
-        size_t start = i;
-        while (_selected.test(i) && i != e) ++i;
-        makeString(sel, newline, start, i - start);
-    }        
+    makeString(sel, newline, true);
     return sel;
 }
 

=== modified file 'libcore/asobj/TextSnapshot_as.h'
--- a/libcore/asobj/TextSnapshot_as.h   2009-03-10 08:50:13 +0000
+++ b/libcore/asobj/TextSnapshot_as.h   2009-03-11 10:14:31 +0000
@@ -20,12 +20,11 @@
 #define GNASH_ASOBJ_TEXTSNAPSHOT_H
 
 #include "as_object.h"
-#include <boost/dynamic_bitset.hpp>
 
 
 // Forward declarations.
 namespace gnash {
-    class generic_character;
+    class StaticText;
     class Array_as;
     namespace SWF {
         class TextRecord;
@@ -44,7 +43,7 @@
     /// 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*, Records> > TextFields;
+    typedef std::vector<std::pair<StaticText*, Records> > TextFields;
 
     /// Construct a TextSnapshot_as from a MovieClip.
     //
@@ -79,7 +78,17 @@
 
 private:
 
+    /// Generate a string from the TextRecords in this TextSnapshot.
+    //
+    /// @param to           The string to write to
+    /// @param newline      If true, newlines are written after every
+    ///                     StaticText in this TextSnapshot
+    /// @param selectedOnly Only write character that are selected to.
+    /// @param start        The start index
+    /// @param len          The number of StaticText characters to traverse.
+    ///                     This includes non-selected characters.
     void makeString(std::string& to, bool newline = false,
+            bool selectedOnly = false,
             std::string::size_type start = 0,
             std::string::size_type len = std::string::npos) const;
 
@@ -97,15 +106,6 @@
     /// afresh every time.
     const size_t _count;
 
-    /// Characters in the text run are selected individually.
-    //
-    /// Storing selection information along with the characters themselves
-    /// means that a separate object is necessary for each character.
-    /// Using a dynamic bitset prevents this, and generally
-    /// saves a lot of memory (32 bytes for boost's dynamic bitset against
-    /// one byte per character, possibly packed, for a bool in an object).
-    boost::dynamic_bitset<> _selected;
-
 };
 
 } // end of gnash namespace

=== modified file 'libcore/character.h'
--- a/libcore/character.h       2009-03-09 14:22:03 +0000
+++ b/libcore/character.h       2009-03-11 10:14:31 +0000
@@ -49,7 +49,7 @@
     class ExecutableCode;
     class action_buffer;
     class movie_definition;
-    class generic_character;
+    class StaticText;
     namespace SWF {
         class TextRecord;
     }
@@ -417,9 +417,9 @@
     /// Allow extraction of static text.
     //
     /// Default is a no-op, implemented only for DefineText though
-    /// generic_character.
-    virtual generic_character* getStaticText(
-            std::vector<const SWF::TextRecord*>& /*to*/) {
+    /// DisplayObject.
+    virtual StaticText* getStaticText(std::vector<const SWF::TextRecord*>&,
+            size_t&) {
         return 0;
     }
 

=== removed file 'libcore/generic_character.cpp'
--- a/libcore/generic_character.cpp     2009-03-09 14:22:03 +0000
+++ b/libcore/generic_character.cpp     1970-01-01 00:00:00 +0000
@@ -1,71 +0,0 @@
-// generic_character.cpp:  Mouse/Character handling, 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
-//
-
-#include "generic_character.h"
-
-namespace gnash
-{
-
-void
-generic_character::add_invalidated_bounds(InvalidatedRanges& ranges, 
-  bool force)
-{
-  ranges.add(m_old_invalidated_ranges);
-  if (isVisible() && (m_invalidated||force))
-  {
-    rect bounds;    
-    bounds.expand_to_transformed_rect(getWorldMatrix(), 
-      m_def->get_bound());
-    ranges.add(bounds.getRange());            
-  }    
-}
-
-
-bool
-generic_character::pointInShape(boost::int32_t  x, boost::int32_t  y) const
-{
-  SWFMatrix wm = getWorldMatrix();
-  SWFMatrix wm_inverse = wm.invert();
-  point  lp(x, y);
-  wm_inverse.transform(lp);
-  return m_def->point_test_local(lp.x, lp.y, wm);
-}
-
-
-generic_character*
-generic_character::getStaticText(std::vector<const SWF::TextRecord*>& to)
-{
-    if (m_def->extractStaticText(to)) return this;
-    return 0;
-}
-
-void  
-generic_character::display()
-{
-  m_def->display(this); // pass in transform info
-  
-  clear_invalidated();
-}
-
-} // namespace gnash
-
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:

=== removed file 'libcore/generic_character.h'
--- a/libcore/generic_character.h       2009-03-09 14:22:03 +0000
+++ b/libcore/generic_character.h       1970-01-01 00:00:00 +0000
@@ -1,124 +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_GENERIC_CHARACTER_H
-#define GNASH_GENERIC_CHARACTER_H
-
-#include "smart_ptr.h" // GNASH_USE_GC
-#include "character.h" // for inheritance
-#include "shape_character_def.h" // for add_invalidated_bounds 
-
-#include <cassert>
-
-namespace gnash {
-
-    // Forward declarations
-    class character_def;
-
-    namespace SWF {
-        class TextRecord;
-    }
-
-}
-
-namespace gnash {
-
-/// For characters that don't store unusual state in their instances.
-//
-/// @@AFAICT this is only used for shape characters
-///
-class generic_character : public character
-{
-
-protected:
-
-       boost::intrusive_ptr<character_def> m_def;
-
-#ifdef GNASH_USE_GC
-       /// Mark reachabe resources (for the GC)
-       //
-       /// These are:
-       ///     - this char's definition (m_def)
-       ///
-       void markReachableResources() const
-       {
-               assert(isReachable());
-               m_def->setReachable();
-
-               markCharacterReachable();
-       }
-#endif // GNASH_USE_GC
-
-public:
-
-       generic_character(character_def* def, character* parent, int id)
-               :
-               character(parent, id),
-               m_def(def)
-       {
-           assert(m_def);
-       }
-
-       /// generic characters can not handle mouse events, so
-       /// the default implementation returns false.
-       /// override in your subclass to change this
-       virtual bool can_handle_mouse_event() const {
-               return false;
-       }
-
-    virtual generic_character* getStaticText(
-            std::vector<const SWF::TextRecord*>& /*to*/);
-
-       virtual void display();
-
-       rect getBounds() const
-       {
-               return m_def->get_bound();
-       }
-
-       /// Generic character is NEVER a mouse entity by default, so
-       /// the default implementation of this method always returns NULL.
-       /// Override it from subclasses that do can be mouse entities.
-       ///
-       /// If you need to check for a generic character to contain a 
-       /// given point, use the pointInShape() function instead.
-       /// 
-       virtual character* get_topmost_mouse_entity(boost::int32_t /*x*/, 
-            boost::int32_t /*y*/)
-       {
-               return NULL;
-       }
-
-       // See dox in character.h
-       virtual bool pointInShape(boost::int32_t  x, boost::int32_t  y) const;
-
-       void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
-    
-
-};
-
-
-}      // end namespace gnash
-
-
-#endif // GNASH_GENERIC_CHARACTER_H
-
-
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:

=== modified file 'libcore/parser/BitmapMovieDefinition.cpp'
--- a/libcore/parser/BitmapMovieDefinition.cpp  2009-02-25 22:33:03 +0000
+++ b/libcore/parser/BitmapMovieDefinition.cpp  2009-03-10 20:43:50 +0000
@@ -21,14 +21,13 @@
 #include "BitmapMovieInstance.h"
 #include "BitmapMovieDefinition.h"
 #include "fill_style.h"
-#include "shape.h" // for class path and class edge
+#include "Geometry.h" // for class path and class edge
 #include "render.h" // for ::display
 #include "GnashImage.h"
 #include "log.h"
 
 namespace gnash {
 
-
 shape_character_def*
 BitmapMovieDefinition::getShapeDef()
 {

=== modified file 'libcore/parser/BitmapMovieDefinition.h'
--- a/libcore/parser/BitmapMovieDefinition.h    2009-02-25 22:33:03 +0000
+++ b/libcore/parser/BitmapMovieDefinition.h    2009-03-10 20:43:50 +0000
@@ -54,7 +54,12 @@
        ///  - image->size() bytes (for get_bytes_loaded()/get_bytes_total())
        ///  - provided url
        ///
-       BitmapMovieDefinition(std::auto_ptr<GnashImage> image, const 
std::string& url);
+       BitmapMovieDefinition(std::auto_ptr<GnashImage> image,
+            const std::string& url);
+
+    virtual character* createDisplayObject(character* parent, int id) {
+        return 0;
+    }
 
        // Discard id, always return the only shape character we have 
        virtual character_def* get_character_def(int /*id*/)

=== modified file 'libcore/parser/SWFMovieDefinition.h'
--- a/libcore/parser/SWFMovieDefinition.h       2009-02-25 22:33:03 +0000
+++ b/libcore/parser/SWFMovieDefinition.h       2009-03-10 20:43:50 +0000
@@ -385,12 +385,16 @@
        ///
        movie_instance* create_movie_instance(character* parent=0);
 
+    virtual character* createDisplayObject(character* parent, int id) {
+        return 0;
+    }
+
        virtual const std::string& get_url() const { return _url; }
        
        const rect&     get_bound() const {
     // It is required that get_bound() is implemented in character definition
     // classes. However, it makes no sense to call it for movie interfaces.
-    // get_bound() is currently only used by generic_character which normally
+    // get_bound() is currently only used by DisplayObject which normally
     // is used only shape character definitions. See character_def.h to learn
     // why it is virtual anyway.
     abort(); // should not be called  

=== modified file 'libcore/parser/character_def.cpp'
--- a/libcore/parser/character_def.cpp  2009-02-09 03:22:05 +0000
+++ b/libcore/parser/character_def.cpp  2009-03-10 20:43:50 +0000
@@ -21,18 +21,11 @@
 #endif
 
 #include "character_def.h"
-#include "generic_character.h"
 #include "render_handler.h" // for destruction of render_cache_manager
 
 namespace gnash
 {
 
-character*
-character_def::create_character_instance(character* parent, int id)
-{
-       return new generic_character(this, parent, id);
-}
-
 character_def::~character_def()
 {
        delete m_render_cache;

=== modified file 'libcore/parser/character_def.h'
--- a/libcore/parser/character_def.h    2009-03-09 20:45:43 +0000
+++ b/libcore/parser/character_def.h    2009-03-11 06:34:47 +0000
@@ -64,15 +64,6 @@
        {
        }
 
-    /// 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::vector<const SWF::TextRecord*>& /*to*/)
-    {
-        return false;
-    }
-
        /// Return true if the specified point is on the interior of our shape.
        //
        /// Point coordinates are local coords (TWIPS)
@@ -89,12 +80,11 @@
 
        /// Should stick the result in a boost::intrusive_ptr immediately.
        //
-       /// default is to make a generic_character
+       /// default is to make a DisplayObject
        ///
-       virtual character* create_character_instance(character* parent,
-                       int id);
+       virtual character* createDisplayObject(character* parent, int id) = 0;
        
-       // Declared as virtual here because generic_character needs access to it
+       // Declared as virtual here because DisplayObject needs access to it
        virtual const rect&     get_bound() const = 0;
        
     /// Cache holder for renderer (contents depend on renderer handler)

=== modified file 'libcore/parser/shape_character_def.cpp'
--- a/libcore/parser/shape_character_def.cpp    2009-01-22 20:10:39 +0000
+++ b/libcore/parser/shape_character_def.cpp    2009-03-10 20:43:50 +0000
@@ -28,10 +28,10 @@
 #include "impl.h"
 #include "log.h"
 #include "render.h"
+#include "Shape.h"
 #include "SWFStream.h"
 #include "MovieClip.h"
 
-#include <cfloat>
 #include <algorithm>
 
 // Define the macro below to always compute bounds for shape characters
@@ -41,6 +41,12 @@
 namespace gnash
 {
 
+character*
+shape_character_def::createDisplayObject(character* parent, int id)
+{
+       return new Shape(this, parent, id);
+}
+
 // Read fill styles, and push them onto the given style array.
 static void
 read_fill_styles(std::vector<fill_style>& styles, SWFStream& in,

=== modified file 'libcore/parser/shape_character_def.h'
--- a/libcore/parser/shape_character_def.h      2009-01-22 14:36:37 +0000
+++ b/libcore/parser/shape_character_def.h      2009-03-10 20:43:50 +0000
@@ -11,7 +11,7 @@
 
 #include "character_def.h" // for inheritance of shape_character_def
 #include "smart_ptr.h" // GNASH_USE_GC
-#include "shape.h"     // for path
+#include "Geometry.h"     // for path
 #include "rect.h"      // for composition
 #include "fill_style.h" // for fill style
 #include "styles.h"     // for line style
@@ -53,6 +53,8 @@
     virtual bool point_test_local(boost::int32_t x, boost::int32_t y,
             const SWFMatrix& wm);
 
+       virtual character* createDisplayObject(character* parent, int id);
+       
     /// \brief
     /// Read a shape definition as included in DEFINEFONT*,
     /// DEFINESHAPE* or DEFINEMORPH* tag

=== modified file 'libcore/parser/sprite_definition.cpp'
--- a/libcore/parser/sprite_definition.cpp      2009-01-22 20:10:39 +0000
+++ b/libcore/parser/sprite_definition.cpp      2009-03-10 20:43:50 +0000
@@ -39,14 +39,12 @@
 namespace gnash {
 
 character*
-sprite_definition::create_character_instance(character* parent,
-               int id)
+sprite_definition::createDisplayObject(character* parent, int id)
 {
 #ifdef DEBUG_REGISTER_CLASS
        log_debug(_("Instantiating sprite_def %p"), (void*)this);
 #endif
-       MovieClip* si = new MovieClip(this,
-       parent->get_root(), parent, id);
+       MovieClip* si = new MovieClip(this, parent->get_root(), parent, id);
        return si;
 }
 

=== modified file 'libcore/parser/sprite_definition.h'
--- a/libcore/parser/sprite_definition.h        2009-02-25 22:33:03 +0000
+++ b/libcore/parser/sprite_definition.h        2009-03-10 20:43:50 +0000
@@ -243,8 +243,7 @@
        // the parent movie's display list.
        //
        // overloads from character_def
-       virtual character* create_character_instance(
-               character* parent, int id);
+       virtual character* createDisplayObject(character* parent, int id);
 
 
 private:
@@ -326,7 +325,7 @@
        const rect&     get_bound() const {
     // It is required that get_bound() is implemented in character definition
     // classes. However, it makes no sense to call it for sprite definitions.
-    // get_bound() is currently only used by generic_character which normally
+    // get_bound() is currently only used by DisplayObject which normally
     // is used only shape character definitions. See character_def.h to learn
     // why it is virtual anyway.
     abort(); // should not be called

=== removed file 'libcore/shape.h'
--- a/libcore/shape.h   2009-02-25 22:33:03 +0000
+++ b/libcore/shape.h   1970-01-01 00:00:00 +0000
@@ -1,594 +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_SHAPE_H
-#define GNASH_SHAPE_H
-
-#include "dsodefs.h"
-#include "SWFMatrix.h" 
-
-#include <vector> // for path composition
-#include <cmath> // sqrt
-
-
-// Forward declarations
-namespace gnash {
-  class rect; 
-}
-
-namespace gnash { 
-
-  /// \brief
-  /// Defines an edge with a control point and an anchor point.
-  /// 
-  /// Could be a quadratic bezier curve, or a straight line(degenerated curve).
-  ///
-  class Edge
-  {
-  public:
-       
-    // Quadratic bezier: point = p0 * t^2 + p1 * 2t(1-t) + p2 * (1-t)^2
-    point cp; // control point, TWIPS
-    point ap; // anchor  point, TWIPS
-
-    Edge() 
-        :
-    cp(0, 0), ap(0, 0)
-    {  };
-    
-    Edge(boost::int32_t cx, boost::int32_t cy, boost::int32_t ax, 
boost::int32_t ay)
-      :
-      cp(cx, cy), ap(ax, ay)
-    {  }
-
-    Edge(const Edge& from)
-      : 
-      cp(from.cp), ap(from.ap)
-    {  }
-
-    Edge(const point& ncp, const point& nap)
-      :
-      cp(ncp), ap(nap)
-    {  }
-
-    bool isStraight() const
-    {
-        return cp == ap;
-    }
-
-    // TODO: drop this!
-    bool is_straight() const { return isStraight(); }
-    
-    /// Transform the edge according to the given SWFMatrix.
-    void  transform(const SWFMatrix& mat)
-    {
-        mat.transform(ap);
-        mat.transform(cp);
-    }
-
-    /// Return squared distance between point pt and segment A-B
-    static double
-    squareDistancePtSeg(const point& p, const point& A, const point& B)
-    {
-        boost::int32_t dx = B.x - A.x;
-        boost::int32_t dy = B.y - A.y;
-
-        if ( dx == 0 && dy == 0 ) 
-        {
-            return p.squareDistance(A);
-        }
-
-        boost::int32_t pdx = p.x - A.x;
-        boost::int32_t pdy = p.y - A.y;
-
-        double u = ( (double)(pdx) * dx + (double)(pdy) * dy ) / ( 
(double)(dx)*dx + (double)(dy)*dy );
-
-        if (u <= 0)
-        {
-            return p.squareDistance(A); 
-        }
-
-        if (u >= 1)
-        {
-            return p.squareDistance(B);
-        }
-
-        point px(A, B, u); // FIXME: this interpolation introduce a precision 
loss (point is int-based)
-        return p.squareDistance(px);
-    }
-
-    /// Return distance between point pt and segment A-B
-    static double
-    distancePtSeg(const point& pt, const point& A, const point& B)
-    {
-        double square = squareDistancePtSeg(pt, A, B);
-        return std::sqrt(square);
-    }
-
-    /// Find point of the quadratic curve defined by points A,C,B
-    //
-    /// @param A The first point
-    /// @param C The second point (control point)
-    /// @param B The third point (anchor point)
-    /// @param ret The point to write result into
-    /// @param t the step factor between 0 and 1
-    ///
-
-    static point
-    pointOnCurve(const point& A, 
-        const point& C, 
-        const point& B, float t)
-    {
-        point Q1(A, C, t);
-        point Q2(C, B, t);
-        point R(Q1, Q2, t);
-
-        return R;
-    }
-
-    /// Return square distance between point pt and the point on curve found by
-    /// applying the T parameter to the quadratic bezier curve function
-    //
-    /// @param A The first point of the bezier curve
-    /// @param C The second point of the bezier curve (control point)
-    /// @param B The third point of the bezier curve (anchor point)
-    /// @param p The point we want to compute distance from 
-    /// @param t the step factor between 0 and 1
-    ///
-    static boost::int64_t squareDistancePtCurve(const point& A,
-               const point& C,
-               const point& B,
-               const point& p, float t)
-    {
-      return p.squareDistance( pointOnCurve(A, C, B, t) );
-    }
-  };
-
-
-  ///\brief
-  /// A subset of a shape, a series of edges sharing a single set of styles. 
-  class DSOEXPORT Path
-  {
-  public:
-    /// Left fill style index (1-based)
-    unsigned m_fill0;
-
-    /// Right fill style index (1-based)
-    unsigned m_fill1;
-
-    /// Line style index (1-based)
-    unsigned m_line;
-
-    /// Start point of the path
-    point ap; 
-
-    /// Edges forming the path
-    std::vector<Edge> m_edges;
-
-    /// This flag is set when the path is the first one of a new "sub-shape".
-    /// All paths with a higher index in the list belong to the same 
-    /// shape unless they have m_new_shape==true on their own.
-    /// Sub-shapes affect the order in which outlines and shapes are rendered.
-    bool m_new_shape;
-    
-    /// Default constructor
-    //
-    /// @param newShape
-    ///  True if this path starts a new subshape
-    ///
-    Path(bool newShape = false)
-      : 
-    m_new_shape(newShape)
-    {
-      reset(0, 0, 0, 0, 0);
-    }
-
-    Path(const Path& from)
-      : 
-      m_fill0(from.m_fill0),
-      m_fill1(from.m_fill1),
-      m_line(from.m_line),
-      ap(from.ap),
-      m_edges(from.m_edges),
-      m_new_shape(from.m_new_shape)        
-    {
-    }
-    
-    /// Initialize a path 
-    //
-    /// @param ax
-    ///  X coordinate of path origin in TWIPS
-    ///
-    /// @param ay
-    ///  Y coordinate in path origin in TWIPS
-    ///
-    /// @param fill0
-    ///  Fill style index for left fill (1-based).
-    ///  Zero means NO style.
-    ///
-    /// @param fill1
-    ///  Fill style index for right fill (1-based)
-    ///  Zero means NO style.
-    ///
-    /// @param line
-    ///  Line style index for right fill (1-based).
-    ///  Zero means NO style.
-    ///
-    /// @param newShape
-    ///  True if this path starts a new subshape
-    Path(boost::int32_t ax, boost::int32_t ay, 
-        unsigned fill0, unsigned fill1, unsigned line, 
-        bool newShape)
-      :
-      m_new_shape(newShape)
-    {
-        reset(ax, ay, fill0, fill1, line);
-    }
-
-    /// Re-initialize a path, maintaining the "new shape" flag untouched
-    //
-    /// @param ax
-    ///  X coordinate of path origin in TWIPS
-    ///
-    /// @param ay
-    ///  Y coordinate in path origin in TWIPS
-    ///
-    /// @param fill0
-    ///  Fill style index for left fill
-    ///
-    /// @param fill1
-    ///  Fill style index for right fill
-    //
-    /// @param line
-    ///  Line style index for right fill
-    ///
-    void  reset(boost::int32_t ax, boost::int32_t ay, 
-        unsigned fill0, unsigned fill1, unsigned line)
-    // Reset all our members to the given values, and clear our edge list.
-    {
-        ap.x = ax;
-        ap.y = ay;
-        m_fill0 = fill0;
-        m_fill1 = fill1;
-        m_line = line;
-
-        m_edges.resize(0);
-        assert(is_empty());
-    }
-
-    /// Return true if we have no edges.
-    bool  is_empty() const
-    {
-        return m_edges.empty();
-    }
-
-    /// Expand given rect to include bounds of this path
-    //
-    /// @param r
-    ///  The rectangle to expand with our own bounds
-    ///
-    /// @param thickness
-    ///  The thickess of our lines, half the thickness will
-    ///  be added in all directions in swf8+, all of it will
-    ///  in swf7-
-    ///
-    /// @param swfVersion
-    ///  SWF version to use.
-    ///
-    void
-    expandBounds(rect& r, unsigned int thickness, int swfVersion) const
-    {
-        const Path&  p = *this;
-        size_t nedges = m_edges.size();
-        
-        if ( ! nedges ) return; // this path adds nothing
-
-        if (thickness)
-        {
-            // NOTE: Half of thickness would be enough (and correct) for
-            // radius, but that would not match how Flash calculates the
-            // bounds using the drawing API.                        
-            unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
-
-            r.expand_to_circle(ap.x, ap.y, radius);
-            for (unsigned int j = 0; j<nedges; j++)
-            {
-                r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
-                r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
-            }
-        }
-        else
-        {
-            r.expand_to_point(ap.x, ap.y);
-            for (unsigned int j = 0; j<nedges; j++)
-            {
-                r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
-                r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
-            }
-        }
-    }
-
-    /// @{ Primitives for the Drawing API
-    ///
-    /// Name of these functions track Ming interface
-    ///
-
-    /// Draw a straight line.
-    //
-    /// Point coordinates are relative to path origin
-    /// and expressed in TWIPS.
-    ///
-    /// @param x
-    ///  X coordinate in TWIPS
-    ///
-    /// @param y
-    ///  Y coordinate in TWIPS
-    ///
-    void 
-    drawLineTo(boost::int32_t dx, boost::int32_t dy)
-    {
-        m_edges.push_back(Edge(dx, dy, dx, dy)); 
-    }
-
-    /// Draw a curve.
-    //
-    /// Offset values are relative to path origin and
-    /// expressed in TWIPS.
-    ///
-    /// @param cx
-    ///  Control point's X coordinate.
-    ///
-    /// @param cy
-    ///  Control point's Y coordinate.
-    ///
-    /// @param ax
-    ///  Anchor point's X ordinate.
-    ///
-    /// @param ay
-    ///  Anchor point's Y ordinate.
-    ///
-    void 
-    drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, 
boost::int32_t ady)
-    {
-        m_edges.push_back(Edge(cdx, cdy, adx, ady)); 
-    }
-
-    /// Remove all edges and reset style infomation 
-    void clear()
-    {
-        m_edges.resize(0);
-        m_fill0 = m_fill1 = m_line = 0;
-    }
-
-    /// @} Primitives for the Drawing API
-
-
-    /// Returns true if the last and the first point of the path match
-    bool  isClosed() const 
-    {
-        if ( m_edges.empty() ) 
-        {
-            return true;  
-        }
-        else
-        {
-            return m_edges.back().ap == ap; 
-        }
-    }
-
-    /// Close this path with a straight line, if not already closed
-    void  close()
-    {
-        if ( m_edges.empty() ) return;
-
-        // Close it with a straight edge if needed
-        const Edge& lastedge = m_edges.back();
-        if ( lastedge.ap != ap )
-        {
-            Edge newedge(ap, ap);
-            m_edges.push_back(newedge);
-        }
-    }
-
-    /// \brief
-    /// Return true if the given point is within the given squared distance
-    /// from this path edges.
-    //
-    /// NOTE: if the path is empty, false is returned.
-    ///
-    bool
-    withinSquareDistance(const point& p, double dist) const
-    {
-      size_t nedges = m_edges.size();
-
-      if ( ! nedges ) return false;
-
-      point px(ap);
-      for (size_t i=0; i<nedges; ++i)
-      {
-        const Edge& e = m_edges[i];
-        point np(e.ap);
-
-        if ( e.isStraight() )
-        {
-          double d = Edge::squareDistancePtSeg(p, px, np);
-
-          if ( d <= dist ) return true;
-        }
-        else
-        {
-
-          const point& A = px;
-          const point& C = e.cp;
-          const point& B = e.ap;
-
-          // Approximate the curve to segCount segments
-          // and compute distance of query point from each
-          // segment.
-          //
-          // TODO: find an apprpriate value for segCount based
-          //       on rendering scale ?
-          //
-          int segCount = 10; 
-          point p0(A.x, A.y);
-          for (int i=1; i<=segCount; ++i)
-          {
-            float t1 = (float)(i) / segCount;
-            point p1 = Edge::pointOnCurve(A, C, B, t1);
-
-            // distance from point and segment being an approximation 
-            // of the curve 
-            double d = Edge::squareDistancePtSeg(p, p0, p1);
-            if ( d <= dist ) return true;
-
-            p0.setTo(p1.x, p1.y);
-          }
-        }
-        px = np;
-      }
-
-      return false;
-    }
-
-    /// Transform all path coordinates according to the given SWFMatrix.
-    void  transform(const SWFMatrix& mat)
-    {
-               mat.transform(ap);
-               std::vector<Edge>::iterator it = m_edges.begin(), ie = 
m_edges.end();
-               for(; it != ie; it++)
-               {
-                       (*it).transform(mat);
-               }
-    }    
-
-    /// Set this path as the start of a new (sub)shape
-    void  setNewShape() 
-    { 
-        m_new_shape=true; 
-    }
-
-    /// Return true if this path starts a new (sub)shape
-    bool  getNewShape() const 
-    { 
-        return m_new_shape; 
-    }
-
-    /// Return true if this path contains no edges
-    bool  empty() const
-    {
-        return is_empty();
-    }
-
-    /// Set the fill to use on the left side
-    //
-    /// @param f
-    ///  The fill index (1-based).
-    ///  When this path is added to a shape_character_def,
-    ///  the index (decremented by 1) will reference an element
-    ///  in the fill_style vector defined for that shape.
-    ///  If zero, no fill will be active.
-    ///
-    void setLeftFill(unsigned f)
-    {
-        m_fill0 = f;
-    }
-
-    unsigned getLeftFill() const
-    {
-        return m_fill0;
-    }
-
-    /// Set the fill to use on the left side
-    //
-    /// @param f
-    ///  The fill index (1-based).
-    ///  When this path is added to a shape_character_def,
-    ///  the index (decremented by 1) will reference an element
-    ///  in the fill_style vector defined for that shape.
-    ///  If zero, no fill will be active.
-    ///
-    void setRightFill(unsigned f)
-    {
-        m_fill1 = f;
-    }
-
-    unsigned getRightFill() const
-    {
-        return m_fill1;
-    }
-
-    /// Set the line style to use for this path
-    //
-    /// @param f
-    ///  The line_style index (1-based).
-    ///  When this path is added to a shape_character_def,
-    ///  the index (decremented by 1) will reference an element
-    ///  in the line_style vector defined for that shape.
-    ///  If zero, no fill will be active.
-    ///
-    void setLineStyle(unsigned i)
-    {
-        m_line = i;
-    }
-
-    unsigned getLineStyle() const
-    {
-        return m_line;
-    }
-
-    /// Return the number of edges in this path
-    size_t size() const
-    {
-        return m_edges.size();
-    }
-
-    /// Return a reference to the Nth edge 
-    Edge& operator[] (size_t n)
-    {
-        return m_edges[n];
-    }
-
-    /// Return a const reference to the Nth edge 
-    const Edge& operator[] (size_t n) const
-    {
-        return m_edges[n];
-    }
-
-    /// Returns true if this path begins a new subshape. <-- VERIFYME
-    bool isNewShape() const
-    {
-        return m_new_shape;
-    }
- 
-  }; // end of class Path
-
-
-  typedef Edge  edge;
-  typedef Path  path;
-
-}  // end namespace gnash
-
-#endif // GNASH_SHAPE_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8 
-// tab-width: 8
-// indent-tabs-mode: t
-// End:

=== modified file 'libcore/swf/DefineButtonTag.cpp'
--- a/libcore/swf/DefineButtonTag.cpp   2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineButtonTag.cpp   2009-03-10 20:43:50 +0000
@@ -22,7 +22,7 @@
 
 #include "smart_ptr.h" // GNASH_USE_GC
 #include "DefineButtonTag.h"
-#include "Button.h" // for create_character_instance()
+#include "Button.h" // for createDisplayObject()
 #include "DefineButtonCxformTag.h"
 #include "swf.h"
 #include "SWFStream.h" // for read()
@@ -419,7 +419,7 @@
 
 
 character*
-DefineButtonTag::create_character_instance(character* parent, int id)
+DefineButtonTag::createDisplayObject(character* parent, int id)
 {
        character* ch = new Button(*this, parent, id);
        return ch;

=== modified file 'libcore/swf/DefineButtonTag.h'
--- a/libcore/swf/DefineButtonTag.h     2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineButtonTag.h     2009-03-10 20:43:50 +0000
@@ -193,14 +193,14 @@
        virtual ~DefineButtonTag();
 
        /// Create a mutable instance of our definition.
-       character* create_character_instance(character* parent, int id);
+       character* createDisplayObject(character* parent, int id);
 
        const rect&     get_bound() const {
                // It is required that get_bound() is implemented in character
         // definition classes. However, button character definitions do
         // not have shape definitions themselves. Instead, they hold a list
         // of shape_character_def. get_bound() is currently only used
-        // by generic_character which normally is used only shape character
+        // by DisplayObject which normally is used only shape character
         // definitions. See character_def.h to learn why it is virtual anyway.
                // get_button_bound() is used for buttons.
                abort(); // should not be called  

=== modified file 'libcore/swf/DefineEditTextTag.cpp'
--- a/libcore/swf/DefineEditTextTag.cpp 2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineEditTextTag.cpp 2009-03-10 20:43:50 +0000
@@ -39,7 +39,7 @@
 }
 
 character*
-DefineEditTextTag::create_character_instance(character* parent, int id)
+DefineEditTextTag::createDisplayObject(character* parent, int id)
 {
        // Resolve the font, if possible
        getFont();

=== modified file 'libcore/swf/DefineEditTextTag.h'
--- a/libcore/swf/DefineEditTextTag.h   2009-03-05 09:16:32 +0000
+++ b/libcore/swf/DefineEditTextTag.h   2009-03-10 20:43:50 +0000
@@ -67,7 +67,7 @@
 
     const rect& get_bound() const { return _rect; }
 
-    character* create_character_instance(character* parent, int id);
+    character* createDisplayObject(character* parent, int id);
 
        /// Return a reference to the default text associated
        /// with this EditText definition.

=== modified file 'libcore/swf/DefineFontAlignZonesTag.cpp'
--- a/libcore/swf/DefineFontAlignZonesTag.cpp   2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineFontAlignZonesTag.cpp   2009-03-10 20:43:50 +0000
@@ -20,7 +20,6 @@
 
 #include "Font.h"
 #include "log.h"
-#include "shape.h"
 #include "SWFStream.h"
 #include "movie_definition.h"
 #include "DefineFontAlignZonesTag.h"

=== modified file 'libcore/swf/DefineTextTag.cpp'
--- a/libcore/swf/DefineTextTag.cpp     2009-03-09 14:59:05 +0000
+++ b/libcore/swf/DefineTextTag.cpp     2009-03-11 09:39:20 +0000
@@ -13,6 +13,10 @@
 #include "swf.h"
 #include "TextRecord.h"
 #include "Font.h"
+#include "StaticText.h"
+
+#include <algorithm>
+#include <numeric>
 
 namespace gnash {
 namespace SWF {
@@ -43,14 +47,27 @@
 };
 
 
+character*
+DefineTextTag::createDisplayObject(character* parent, int id)
+{
+    return new StaticText(this, parent, id);
+}
+
+
 bool
-DefineTextTag::extractStaticText(std::vector<const TextRecord*>& to)
+DefineTextTag::extractStaticText(std::vector<const TextRecord*>& to,
+        size_t& numChars)
 {
     if (_textRecords.empty()) return false;
 
+    /// Insert pointers to all our TextRecords into to.
     std::transform(_textRecords.begin(), _textRecords.end(),
             std::back_inserter(to), CreatePointer<TextRecord>());
 
+    /// Count the number of characters in this definition's text records.
+    numChars = std::accumulate(_textRecords.begin(), _textRecords.end(),
+            0, TextRecord::RecordCounter());
+
     return true;
 }
 

=== modified file 'libcore/swf/DefineTextTag.h'
--- a/libcore/swf/DefineTextTag.h       2009-03-09 14:22:03 +0000
+++ b/libcore/swf/DefineTextTag.h       2009-03-11 09:39:20 +0000
@@ -58,7 +58,14 @@
     }
 
     /// Extract static text from TextRecords.
-    bool extractStaticText(std::vector<const TextRecord*>& to);
+    //
+    /// @param to   Will be filled with pointers to TextRecords
+    ///             if any are present
+    /// @param size Will contain the number of characters in this
+    ///             StaticText definition.
+    bool extractStaticText(std::vector<const TextRecord*>& to, size_t& size);
+
+    virtual character* createDisplayObject(character* parent, int id);
 
 private:
 

=== modified file 'libcore/swf/DefineVideoStreamTag.cpp'
--- a/libcore/swf/DefineVideoStreamTag.cpp      2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineVideoStreamTag.cpp      2009-03-10 20:43:50 +0000
@@ -133,7 +133,7 @@
 }
 
 character*
-DefineVideoStreamTag::create_character_instance(character* parent, int id)
+DefineVideoStreamTag::createDisplayObject(character* parent, int id)
 {
        character* ch = new Video(this, parent, id);
        return ch;

=== modified file 'libcore/swf/DefineVideoStreamTag.h'
--- a/libcore/swf/DefineVideoStreamTag.h        2009-01-22 20:10:39 +0000
+++ b/libcore/swf/DefineVideoStreamTag.h        2009-03-10 20:43:50 +0000
@@ -83,7 +83,7 @@
 
        ~DefineVideoStreamTag();
 
-       character* create_character_instance(character* parent, int id);
+       character* createDisplayObject(character* parent, int id);
 
        /// Read tag SWF::DEFINEVIDEOSTREAM 
        //

=== modified file 'libcore/swf/TextRecord.cpp'
--- a/libcore/swf/TextRecord.cpp        2009-03-10 08:50:13 +0000
+++ b/libcore/swf/TextRecord.cpp        2009-03-11 10:36:40 +0000
@@ -235,11 +235,7 @@
                 // Draw the character using the filled outline.
                 if (glyph)
                 {
-#ifdef GNASH_DEBUG_TEXT_RENDERING
-    log_debug(_("render shape glyph using filled outline 
(render::draw_glyph)"));
-#endif
-
-                    gnash::render::draw_glyph(glyph, mat, textColor);
+                    render::draw_glyph(glyph, mat, textColor);
                 }
             }
             x += ge.advance;

=== modified file 'libcore/swf/TextRecord.h'
--- a/libcore/swf/TextRecord.h  2009-03-10 08:50:13 +0000
+++ b/libcore/swf/TextRecord.h  2009-03-11 10:36:40 +0000
@@ -62,7 +62,16 @@
     {}
           
     typedef std::vector<GlyphEntry> Glyphs;  
-    Glyphs _glyphs;
+
+    /// Accumulate the number of glyphs in a TextRecord.
+    struct RecordCounter
+    {
+        size_t operator()(size_t c, const TextRecord& t) {
+            const Glyphs& glyphs = t.glyphs();
+            size_t ret = c + glyphs.size();
+            return ret;
+        }
+    };
     
     /// Read a TextRecord from the stream
     //
@@ -154,6 +163,8 @@
 
 private:
 
+    Glyphs _glyphs;
+    
     /// The text color.
     rgba _color;
 

=== modified file 'libcore/swf/tag_loaders.cpp'
--- a/libcore/swf/tag_loaders.cpp       2009-02-10 11:33:38 +0000
+++ b/libcore/swf/tag_loaders.cpp       2009-03-10 20:43:50 +0000
@@ -30,7 +30,7 @@
 #include "fontlib.h"
 #include "log.h"
 #include "morph2_character_def.h"
-#include "shape.h"
+#include "Geometry.h"
 #include "SWFStream.h"
 #include "styles.h"
 #include "timers.h"

=== modified file 'testsuite/DummyMovieDefinition.h'
--- a/testsuite/DummyMovieDefinition.h  2009-02-25 22:33:03 +0000
+++ b/testsuite/DummyMovieDefinition.h  2009-03-11 06:34:47 +0000
@@ -50,6 +50,8 @@
 
 public:
 
+    virtual character* createDisplayObject(character*, int id) { return 0; }
+
 
        /// Default constructor
        //

=== modified file 'testsuite/libcore.all/EdgeTest.cpp'
--- a/testsuite/libcore.all/EdgeTest.cpp        2009-02-25 22:33:03 +0000
+++ b/testsuite/libcore.all/EdgeTest.cpp        2009-03-10 20:43:50 +0000
@@ -20,7 +20,7 @@
 #endif
 
 #include "gnash.h" // for point !!
-#include "shape.h" // for edge
+#include "Geometry.h" // for edge
 #include <iostream>
 #include <sstream>
 #include <cassert>

=== modified file 'testsuite/misc-ming.all/TextSnapshotTest.c'
--- a/testsuite/misc-ming.all/TextSnapshotTest.c        2009-03-10 12:22:29 
+0000
+++ b/testsuite/misc-ming.all/TextSnapshotTest.c        2009-03-11 10:16:46 
+0000
@@ -184,7 +184,7 @@
   // Selected text is stored in the textfield and reset when a new
   // snapshot is taken.
   add_actions(mo, "ts2 = new TextSnapshot(this);");
-  xcheck_equals(mo, "ts.getSelectedText(false)", "''");
+  check_equals(mo, "ts.getSelectedText(false)", "''");
   check_equals(mo, "ts2.getCount()", "64");
   check_equals(mo, "ts2.getSelectedText()", "''");
   add_actions(mo, "ts2 = this.getTextSnapshot();");
@@ -193,12 +193,12 @@
 
   add_actions(mo, "ts2.setSelected(3, 10, true);");
   check_equals(mo, "ts2.getSelectedText(false).length", "7");
-  xcheck_equals(mo, "ts.getSelectedText(false).length", "7");
+  check_equals(mo, "ts.getSelectedText(false).length", "7");
 
   add_actions(mo, "ts.setSelectedColor(0xffff00);");
   add_actions(mo, "ts2.setSelectedColor(0x0000ff);");
 
-  xcheck_equals(mo, "ts.getSelectedText(false)", "'st text'");
+  check_equals(mo, "ts.getSelectedText(false)", "'st text'");
   add_actions(mo, "ri = ts.getTextRunInfo(4, 10);");
   check_equals(mo, "typeof(ri)", "'object'");
   check(mo, "ri instanceof Array");
@@ -238,7 +238,7 @@
   check_equals(mo, "ri[3].selected", "true");
   check_equals(mo, "ri[4].selected", "true");
   check_equals(mo, "ri[5].selected", "true");
-  xcheck_equals(mo, "ri[6].selected", "false");
+  check_equals(mo, "ri[6].selected", "false");
 
   check_equals(mo, "ri[2].matrix_tx", "29.75");
   check_equals(mo, "ri[2].matrix_ty", "200");
@@ -260,7 +260,7 @@
 
   add_actions(mo, "ts.setSelected(0, 10, true);");
   add_actions(mo, "ts.setSelected(15, 20, false);");
-  xcheck_equals(mo, "ts2.getSelectedText().length", "10");
+  check_equals(mo, "ts2.getSelectedText().length", "10");
 
   add_actions(mo, "ri2 = ts.getTextRunInfo(0, 100);");
 


reply via email to

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