gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r10545: Implement and test _quality


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10545: Implement and test _quality and _highquality, currently only settable from
Date: Fri, 16 Jan 2009 20:37:33 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10545
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Fri 2009-01-16 20:37:33 +0100
message:
  Implement and test _quality and _highquality, currently only settable from
  MovieClips. There is presently no manual override, but this will be trivial to
  implement.
  
  Implement Video.smoothing, which makes YouTube look more attractive in 
  the AGG renderer. Because this also depends on the _quality / _highquality
  setting, it can still only be set via ActionScript.
  
  Tidy up render_handler.h. Since the Gnash VM will have to be more closely
  integrated with the render_handler, new code is not in the proxy
  libcore/render.h, but rather in render_handler.h.
  
  Remove anti-aliasing flag and other related, renderer-specific enums from
  the render_handler base class- Renderers should now query the _quality
  member when deciding how to render; details of how they do it should
  be kept internal and not pollute the renderer API.
  
  Use a new VideoRenderer class in the AGG backend for drawing video frames. 
This
  may be used to keep instances alive across frames if necessary. Its interface
  needs more improvement. 
modified:
  backend/render_handler.h
  backend/render_handler_agg.cpp
  backend/render_handler_cairo.cpp
  backend/render_handler_ogl.cpp
  backend/render_handler_ogl.h
  cygnal/Makefile.am
  libcore/MovieClip.cpp
  libcore/Video.cpp
  libcore/Video.h
  libcore/character.cpp
  libcore/character.h
  libcore/movie_root.cpp
  libcore/movie_root.h
  libcore/render.cpp
  libcore/render.h
  testsuite/actionscript.all/MovieClip.as
  testsuite/libcore.all/Makefile.am
  utilities/Makefile.am
    ------------------------------------------------------------
    revno: 10544.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 12:06:01 +0100
    message:
      Start implementation of a quality setting. Clean up render_handler header
      so it looks more like an interface.
    modified:
      backend/render_handler.h
      backend/render_handler_ogl.cpp
    ------------------------------------------------------------
    revno: 10544.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 12:55:51 +0100
    message:
      Cleanup.
    modified:
      backend/render_handler_agg.cpp
    ------------------------------------------------------------
    revno: 10544.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 13:00:16 +0100
    message:
      Typedef ClipBounds.
    modified:
      backend/render_handler_agg.cpp
    ------------------------------------------------------------
    revno: 10544.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 14:03:54 +0100
    message:
      Introduce VideoRenderer class.
    modified:
      backend/render_handler_agg.cpp
    ------------------------------------------------------------
    revno: 10544.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 14:21:07 +0100
    message:
      Move typedefs, and don't divide by 20.0 only to multiply by 20.0 again.
    modified:
      backend/render_handler_agg.cpp
    ------------------------------------------------------------
    revno: 10544.1.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 15:45:08 +0100
    message:
      Add templated functions for rendering video with different quality.
    modified:
      backend/render_handler_agg.cpp
    ------------------------------------------------------------
    revno: 10544.1.7
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 17:13:37 +0100
    message:
      Improve _highquality getter/setter, test _quality.
    modified:
      backend/render_handler.h
      backend/render_handler_agg.cpp
      cygnal/Makefile.am
      libcore/MovieClip.cpp
      libcore/character.cpp
      libcore/character.h
      libcore/movie_root.cpp
      libcore/movie_root.h
      testsuite/actionscript.all/MovieClip.as
      utilities/Makefile.am
    ------------------------------------------------------------
    revno: 10544.1.8
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 17:24:25 +0100
    message:
      Implement _quality for MovieClips (not yet Buttons or TextFields), 
      correct initialization order in agg (hard to spot these errors amongst all
      the agg warnings).
    modified:
      backend/render_handler_agg.cpp
      libcore/MovieClip.cpp
      libcore/character.cpp
      libcore/character.h
    ------------------------------------------------------------
    revno: 10544.1.9
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 17:30:00 +0100
    message:
      Fix testsuite run again.
    modified:
      testsuite/libcore.all/Makefile.am
    ------------------------------------------------------------
    revno: 10544.1.10
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 17:55:03 +0100
    message:
      Fix OGL build again.
    modified:
      backend/render_handler_agg.cpp
      backend/render_handler_ogl.cpp
      backend/render_handler_ogl.h
    ------------------------------------------------------------
    revno: 10544.1.11
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 19:00:27 +0100
    message:
      Implement Video.smoothing, and only use high-quality interpolation when
      smoothing is requested and quality is HIGH or BEST.
    modified:
      backend/render_handler.h
      backend/render_handler_agg.cpp
      libcore/Video.cpp
      libcore/Video.h
      libcore/render.cpp
      libcore/render.h
    ------------------------------------------------------------
    revno: 10544.1.12
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 19:17:27 +0100
    message:
      Update drawVideoFrame signature.
    modified:
      backend/render_handler_cairo.cpp
      backend/render_handler_ogl.cpp
    ------------------------------------------------------------
    revno: 10544.1.13
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 20:01:25 +0100
    message:
      Video.smoothing and Video.deblocking shouldn't be read-only. Fixes
      YouTube (and any other SWF using smoothing).
    modified:
      libcore/Video.cpp
    ------------------------------------------------------------
    revno: 10544.1.14
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2009-01-16 20:13:21 +0100
    message:
      Silence debugging.
    modified:
      libcore/Video.cpp
=== modified file 'backend/render_handler.h'
--- a/backend/render_handler.h  2008-12-17 07:54:39 +0000
+++ b/backend/render_handler.h  2009-01-16 18:00:27 +0000
@@ -1,5 +1,5 @@
 // 
-//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//     Copyright (C) 2005, 2006, 2007, 2008 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
@@ -8,12 +8,12 @@
 // 
 // 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
+// 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
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA    02110-1301    
USA
 
 // 
 //
@@ -36,7 +36,7 @@
 ///   *no* primitive objects like circles, rectangles or similar. These 
objects 
 ///   are always translated to lines and curves (a circle is a set of eight 
 ///   curves).
-///            
+/// 
 /// - All paths together must by definition always build a fully closed shape. 
 ///   You can't draw a rectangle with three edges, for example, contrary to 
 ///   most graphics library polygon routines that connect the last anchor to
@@ -53,50 +53,50 @@
 ///   wish).
 ///
 /// - Paths are *never* self-intersecting. 
-///   
+/// 
 ///  Simple examples to understand this concept:
 ///
 ///  - A rectangle that contains another rectangle. Only the area between the 
 ///    two rectangles is filled (so it looks like a "o"). In this case Flash
-///    fill create two paths (one for each rectangle) and one fill style. 
Assume
-///    both paths come in clockwise order, then the outer rectangle will have
-///    fillstyle0=0 and fillstyle1=1. The inner rectangle will have 
+///    fill create two paths (one for each rectangle) and one fill style.
+///    Assume both paths come in clockwise order, then the outer rectangle
+///    will have fillstyle0=0 and fillstyle1=1. The inner rectangle will have 
 ///    fillstyle0=1 and fillstyle1=0.
 ///
 /// \code
-///      +--------------------------------+
-///      |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
-///      |XXX+------------------------+XXX|
-///      |XXX|                        |XXX|
-///      |XXX+------------------------+XXX|
-///      |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
-///      +--------------------------------+
+///            +--------------------------------+
+///            |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+///            |XXX+------------------------+XXX|
+///            |XXX|                        |XXX|
+///            |XXX+------------------------+XXX|
+///            |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
+///            +--------------------------------+
 /// \endcode
 ///
 ///  - A rectangle is divided vertically in two halves, both having different
 ///    colors:
 ///
 /// \code
-///      +-------A-------+-------B--------+
-///      |...............|################|
-///      A...............C################B
-///      |...............|################|
-///      +-------A-------+-------B--------+
+///            +-------A-------+-------B--------+
+///            |...............|################|
+///            A...............C################B
+///            |...............|################|
+///            +-------A-------+-------B--------+
 /// \endcode
 ///
-///    Flash will probably produce three paths (A,B,C) and two fill styles.
-///    Paths "A" and "B" will have just one fill style (fillstyle1 will be 
-///    zero) while path "C" (which contains only one straight line!!) will
-///    have two fill styles. To be exact the horizontal edges would not even
-///    be necessary to render this shape (for a scanline based renderer) but 
-///    they are necessary then the character is about to be rotated.
+///        Flash will probably produce three paths (A,B,C) and two fill styles.
+///        Paths "A" and "B" will have just one fill style (fillstyle1 will be 
+///        zero) while path "C" (which contains only one straight line!!) will
+///        have two fill styles. To be exact the horizontal edges would not 
even
+///        be necessary to render this shape (for a scanline based renderer) 
but 
+///        they are necessary then the character is about to be rotated.
 ///
 /// Now, these are simple examples but complex graphics can be compressed very
 /// efficiently this way. Also, this method was most probably intended for a
 /// renderer engine that can produce the final character in just one pass 
-/// (like the AGG backend does too).    
+/// (like the AGG backend does too).        
 
-  
+    
 /// \page region_update Detection of updated regions
 ///
 /// (this applies to the whole Gnash playback architecture)
@@ -145,11 +145,10 @@
 
 #include "dsodefs.h" // for DSOEXPORT
 
-#include "shape_character_def.h"  
+#include "shape_character_def.h"    
 #include "generic_character.h"
 #include "Range2d.h"
 
-
 // Forward declarations.
 namespace gnash {
     class BitmapInfo;
@@ -161,36 +160,23 @@
     class shape_character_def;
     class generic_character;
 
-    // @@ forward decl to avoid including base/image.h; TODO change the
-    // render_handler interface to not depend on these classes at all.
     class GnashImage;
-    class ImageRGB;
-    class ImageRGBA;
 }
 
 namespace gnash {
 
-/*
-// Base class for renderer general cache objects
-class render_cache_object
-{
-  
-}
-*/
-
-
 class DSOEXPORT render_cache_manager
 {
 public:
-  //Virtual dtor, removes compiler warning.
-  virtual ~render_cache_manager(){}
+    //Virtual dtor, removes compiler warning.
+    virtual ~render_cache_manager(){}
 
-  /// Clears the cache completely (necessary for runtime shapes / drawing API)
-  virtual void clear() 
-  {
-    // TODO: Make this abstract to force real implementation!!
-    // nop
-  } 
+    /// Clears the cache completely (necessary for runtime shapes / drawing 
API)
+    virtual void clear() 
+    {
+        // TODO: Make this abstract to force real implementation!!
+        // nop
+    } 
 };
 
 
@@ -205,409 +191,442 @@
 class DSOEXPORT render_handler
 {
 public:
-  enum antialias_method
-  {
-    ANTIALIAS_DEFAULT, // Whatever the renderer prefers
-    ANTIALIAS_NONE,    // Disabled
-
-    ANTIALIAS_MULTISAMPLE, // OpenGL ARB_multisample extension
-    ANTIALIAS_ACCUM,       // OpenGL accumulation buffer
-
-    ANTIALIAS_GRAY        // Cairo single-color antialiasing
-  };
- 
-  virtual ~render_handler() {}
-
-  /// \brief
-  /// Given an image, returns a pointer to a bitmap_info class
-  /// that can later be passed to fill_styleX_bitmap(), to set a
-  /// bitmap fill style.
-  virtual BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im) = 0;
-
-  /// Draws a video frame. 
-  //
-  /// The frame has already been decoded and is available in RGB format only.  
  
-  ///         
-  /// @param frame The RGB video buffer frame.
-  ///   Ownership of the buffer is left to the caller.
-  ///
-  /// @param mat The SWFMatrix with world coordinates used to retrieve the x
-  ///   and y coordinate of the video object. The scaling of the SWFMatrix only
-  ///   refers to the Flash instance, *not* to the video inside that instance.
-  ///   When a video object is placed on the stage and the loaded video is
-  ///   smaller, then the SWFMatrix is still an "identity SWFMatrix". However, 
if
-  ///   the video object is scaled via ActionScript, for example, then the
-  ///   SWFMatrix will change. This means the renderer has to find the correct
-  ///   scaling for the video inside the bounds.                               
 
-  ///
-  /// @param bounds The minX/minY fields of this rect are always zero. 
-  ///   The width and height determine the size of the Flash video instance
-  ///   on the stage (in TWIPS) prior to SWFMatrix transformations.         
-  ///
-  virtual void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat, const 
rect* bounds) = 0;
-
-  /// Sets the update region (called prior to begin_display).
-  //
-  /// The renderer 
-  /// might do clipping and leave the region outside these bounds unchanged,
-  /// but he is allowed to change them if that makes sense. After rendering
-  /// a frame the area outside the invalidated region can be undefined and 
-  /// is not used. 
-  ///
-  /// It is not required for all renderers.
-  /// Parameters are world coordinates (TWIPS).
-  ///
-  /// For more info see page \ref region_update.
-  ///
-  virtual void set_invalidated_region(const rect& /*bounds*/) {    
-    // implementation is optional    
-  }
-
-  virtual void set_invalidated_regions(const InvalidatedRanges& /*ranges*/) {  
  
-    // implementation is optional    
-  }
-  
-  /// Converts world coordinates to pixel coordinates
-  virtual geometry::Range2d<int> world_to_pixel(const rect& worldbounds) = 0;
-  
-  /// Converts pixel coordinates to world coordinates (TWIPS)
-  virtual point pixel_to_world(int x, int y) = 0;
-  
-  virtual geometry::Range2d<float> pixel_to_world(const 
geometry::Range2d<int>& pixelbounds)
-  {
-    point topleft     = pixel_to_world(pixelbounds.getMinX(), 
pixelbounds.getMinY());
-    point bottomright = pixel_to_world(pixelbounds.getMaxX(), 
pixelbounds.getMaxY());
-    
-    return geometry::Range2d<float> (topleft.x, topleft.y, 
-      bottomright.x, bottomright.y);
-  }
-  
-  virtual geometry::Range2d<int> world_to_pixel(const 
geometry::Range2d<float>& worldbounds)
-  {
-      if ((worldbounds.isNull() || worldbounds.isWorld()))  
-        return worldbounds;
-
-    return world_to_pixel(rect(worldbounds.getMinX(), worldbounds.getMinY(),
-                               worldbounds.getMaxX(), worldbounds.getMaxY())); 
 
-  }
-  
-    
-  /// Bracket the displaying of a frame from a movie.
-  //
-  /// Set up to render a full frame from a movie and fills the
-  /// background. Sets up necessary transforms, to scale the
-  /// movie to fit within the given dimensions.  Call
-  /// end_display() when you're done.
-  ///
-  /// The rectangle (viewport_x0, viewport_y0, viewport_x0 +
-  /// viewport_width, viewport_y0 + viewport_height) defines the
-  /// window coordinates taken up by the movie.
-  ///
-  /// The rectangle (x0, y0, x1, y1) defines the pixel
-  /// coordinates of the movie that correspond to the viewport
-  /// bounds.
-  ///
-  virtual void  begin_display(
-    const rgba& background_color,
-    int viewport_x0, int viewport_y0,
-    int viewport_width, int viewport_height,
-    float x0, float x1, float y0, float y1) = 0;
-
-  virtual void  end_display() = 0;
-    
-  /// Draw a line-strip directly, using a thin, solid line.
-  //
-  /// Can be used to draw empty boxes and cursors.
-  ///
-  /// @coords an array of 16-bit signed integer coordinates. Even indices
-  ///         (and 0) are x coordinates, while uneven ones are y coordinates.
-  ///
-  /// @vertex_count the number of x-y coordinates (vertices).
-  ///
-  /// @color the color to be used to draw the line strip.
-  ///
-  /// @mat the SWFMatrix to be used to transform the vertices.
-  virtual void  draw_line_strip(const boost::int16_t* coords, int vertex_count,
-      const rgba& color, const SWFMatrix& mat) = 0;
-    
-  /// Draw a simple, solid filled polygon with a thin (~1 pixel) outline.
-  //
-  /// This can't be used for 
-  /// Flash shapes but is intended for internal drawings like bounding boxes 
-  /// (editable text fields) and similar. The polygon should not contain 
-  /// self-intersections. If you do not wish a outline or a fill, then simply 
-  /// set the alpha value to zero.
-  ///
-  /// The polygon need NOT be closed (ie: this function will automatically
-  /// add an additional vertex to close it.
-  ///
-  /// When masked==false, then any potential mask currently active will be
-  /// ignored, otherwise it is respected.
-  ///
-  virtual void  draw_poly(const point* corners, size_t corner_count, 
-    const rgba& fill, const rgba& outline, const SWFMatrix& mat, bool masked) 
= 0;
-    
-    
-  /// Set line and fill styles for mesh & line_strip rendering.
-  enum bitmap_wrap_mode
-  {
-    WRAP_REPEAT,
-    WRAP_CLAMP
-  };
-    
-  virtual void  set_antialiased(bool enable) = 0;
-    
-  ///@{ Masks
-  ///
-  /// Masks are defined by drawing calls enclosed by begin_submit_mask()
-  /// and end_submit_mask(). Between these two calls, no drawing is to
-  /// occur. The shapes rendered between the two calls define the
-  /// visible region of the mask. Graphics that are irrelevant in the
-  /// context of a mask (lines and fill styles, for example) should be
-  /// ignored. After use, disable_mask() is called to remove the mask.
-  ///
-  /// Masks may be nested. That is, end_submit_mask() may be followed
-  /// by a call to begin_submit_mask(). The resulting mask shall be an
-  /// intersection of the previously created mask. disable_mask() shall
-  /// result in the disabling or destruction of the last created mask.
-  virtual void begin_submit_mask() = 0;
-  virtual void end_submit_mask() = 0;
-  virtual void disable_mask() = 0;
-  ///@}
-  
-  /// \brief
-  /// Draws the given character definition with the stateful properties
-  /// of the given instance.
-  //
-  /// Normally this does not need to be re-implemented in 
-  /// render handler implementations. Instead, see the version without
-  /// character instance.
-  ///
-  virtual void draw_shape_character(shape_character_def *def, 
-    character *inst)
-  {
-    // check if the character needs to be rendered at all
-    rect cur_bounds;
-
-    cur_bounds.expand_to_transformed_rect(inst->getWorldMatrix(), 
-        def->get_bound());
-        
-    if (!bounds_in_clipping_area(cur_bounds))
-    {
-        return; // no need to draw
-    }    
-
-    // TODO: I don't like that there is a draw_shape_character() version with
-    // arbitrary fill and line styles as this may break caching...
-
-    // render the character
-    draw_shape_character(def, 
-        inst->getWorldMatrix(), 
-        inst->get_world_cxform(),
-        def->get_fill_styles(),
-        def->get_line_styles());
-  }
-  
-  /// \brief
-  /// Checks if the given bounds are (partially) in the current drawing 
clipping
-  /// area.
-  //
-  /// A render handler implementing invalidated bounds should implement
-  /// this method to avoid rendering of characters that are not visible anyway.
-  /// By default this method always returns true, which will ensure correct
-  /// rendering. If possible, it should be re-implemented by the renderer 
-  /// handler for better performance.
-  /// 'bounds' contains TWIPS coordinates.
-  ///
-  /// TODO: Take a Range2d<T> rather then a gnash::rect ?
-  ///       Would T==int be good ? TWIPS as integer types ?
-  ///
-  /// See also gnash::renderer::bounds_in_clipping_area
-  ///
-  virtual bool bounds_in_clipping_area(const rect& bounds) {
-    return bounds_in_clipping_area(bounds.getRange());
-  }
-  
-  virtual bool bounds_in_clipping_area(const InvalidatedRanges& ranges)
-  {
-    for (unsigned int rno=0; rno<ranges.size(); rno++) 
-    {
-      if (bounds_in_clipping_area(ranges.getRange(rno)))
-        return true;
-    }
-        
-    return false;
-  }
-  
-  virtual bool bounds_in_clipping_area(const geometry::Range2d<float>& 
/*bounds*/) {
-    return true;
-  }
-
-  /// \brief
-  /// Draws the given character definition with the given transformations and
-  /// styles. 
-  virtual void draw_shape_character(shape_character_def *def, 
-    const SWFMatrix& mat,
-    const cxform& cx,
-    const std::vector<fill_style>& fill_styles,
-    const std::vector<line_style>& line_styles) = 0;
-    
-  /// \brief
-  /// Draws a glyph (font character).
-  //
-  /// Glyphs are defined just like shape characters with the difference that
-  /// they do not have any fill or line styles.
-  /// Instead, the shape must be drawn using the given color (solid fill).
-  /// Please note that although the glyph paths may indicate subshapes,
-  /// the renderer is to ignore that information.
-  /// 
-  /// @param def
-  ///
-  /// @param mat
-  ///
-  /// @param color
-  virtual void draw_glyph(shape_character_def *def, const SWFMatrix& mat,
-    const rgba& color) = 0;
-
-  /// This function returns the color at any position in the stage. It is used
-  /// for automatic testing only, it should not be used for anything else!
-  /// x and y are pixel coordinates (<0 won't make any sense) and the color of 
-  /// the nearest pixel is returned.
-  /// The function returns false when the coordinates are outside the 
-  /// main frame buffer.
-  virtual bool getPixel(rgba& /*color_return*/, int /*x*/, int /*y*/)
-  {
-
-    log_debug("getPixel() not implemented for this renderer");
-    abort();    
-    return false; // avoid compiler warning    
-  }
-  
-  
-  /// Returns the average RGB color for a square block on the stage. The 
-  /// width and height of the block is defined by "radius" and x/y refer
-  /// to the center of the block. radius==1 equals getPixel() and radius==0
-  /// is illegal. For even "radius" values, the center point is not exactly
-  /// defined. 
-  /// The function returns false when at least one pixel of the block was
-  /// outside the main frame buffer. In that case the value in color_return
-  /// is undefined.
-  /// This implementation is provided for simplicity. Renderers should
-  /// implement a specialized version for better performance.
-  virtual bool getAveragePixel(rgba& color_return, int x, int y, 
-    unsigned int radius)
-  {
-  
-    assert(radius>0); 
-  
-    // optimization:
-    if (radius==1)
-      return getPixel(color_return, x, y);
-  
-    unsigned int r=0, g=0, b=0, a=0;
-    
-    x -= radius/2;
-    y -= radius/2;
-    
-    int xe = x+radius;
-    int ye = y+radius;
-
-    rgba pixel;
-    
-    for (int yp=y; yp<ye; yp++)
-    for (int xp=x; xp<xe; xp++)
-    {
-      if (!getPixel(pixel, xp, yp))
-        return false;
-        
-      r += pixel.m_r;      
-      g += pixel.m_g;      
-      b += pixel.m_b;      
-      a += pixel.m_a;      
-    }
-    
-    int pcount = radius*radius; 
-    color_return.m_r = r / pcount; 
-    color_return.m_g = g / pcount; 
-    color_return.m_b = b / pcount; 
-    color_return.m_a = a / pcount; 
-    
-    return true;
-  }
-  
-  
-  /// \brief
-  /// Initializes the renderer for off-screen rendering used by the  
-  /// testsuite.
-  ///
-  /// This is a special function used for testcases ONLY. It is used by
-  /// MovieTester to prepare the renderer for off-screen rendering 
-  /// without any GUI. The renderer is responsible to do all required
-  /// steps so that rendering is possible after the call. This may mean
-  /// that the renderer allocates memory for the given stage size.
-  /// 
-  /// The function returns false when the renderer is not able to do
-  /// off-screen rendering (default).
-  ///
-  /// Note the function may be called again afterwards, resizing the stage.
-  /// Any number of calls to this function is possible and the renderer
-  /// is responsible to resize any buffer instead of wasting memory. 
-  ///
-  /// @param width stage width in pixels
-  ///
-  /// @param height stage height in pixels
-  virtual bool initTestBuffer(unsigned /*width*/, unsigned /*height*/)
-  {
-    return false;
-  }
-
-  /// Return color depth (bits per pixel) or 0 if unknown/unimplemented.
-  //
-  /// Default implementation returns 0 (unknown).
-  ///
-  /// TODO: this should be a pure abstract function, just don't want
-  ///       to scan ogl and cairo backend for an implementation *now*
-  ///       but would be needed for automated testing... Quinn, can you help ?
-  ///
-  virtual unsigned int getBitsPerPixel() const
-  {
-    return 0;
-  }
-  
-  /// Sets the x/y scale for the movie  
-  virtual void set_scale(float /*xscale*/, float /*yscale*/) {
-    // nop
-  }
-
-  /// Sets the x/y offset for the movie  
-  virtual void set_translation(float /*xoff*/, float /*yoff*/) {
-    // nop
-  }
+
+    /// The display quality.
+    //
+    enum Quality
+    {
+        QUALITY_LOW,
+        QUALITY_MEDIUM,
+        QUALITY_HIGH,
+        QUALITY_BEST
+    };
+
+    render_handler()
+        :
+        _quality(QUALITY_HIGH)
+    {}
+
+    virtual ~render_handler() {}
+
+    /// ==================================================================
+    /// Interfaces for adjusting renderer output.
+    /// ==================================================================
+
+    /// Sets the x/y scale for the movie    
+    virtual void set_scale(float /*xscale*/, float /*yscale*/) {} 
+
+    /// Sets the x/y offset for the movie    
+    virtual void set_translation(float /*xoff*/, float /*yoff*/) {}
+
+    void setQuality(Quality q) { _quality = q; }
+        
+    /// ==================================================================
+    /// Caching utitilies for core.
+    /// ==================================================================
+    
+    /// \brief
+    /// Given an image, returns a pointer to a bitmap_info class
+    /// that can later be passed to fill_styleX_bitmap(), to set a
+    /// bitmap fill style.
+    virtual BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im) = 0;
+
+
+    /// ==================================================================
+    /// Rendering Interface.
+    /// ==================================================================
+
+    /// Draws a video frame.  
+    //
+    /// The frame has already been decoded and is available in RGB format 
only. 
+    ///         
+    /// @param frame The RGB video buffer frame.
+    ///   Ownership of the buffer is left to the caller.
+    ///
+    /// @param mat The SWFMatrix with world coordinates used to retrieve the x
+    ///   and y coordinate of the video object. The scaling of the SWFMatrix
+    ///   only refers to the Flash instance, *not* to the video inside that
+    ///   instance. When a video object is placed on the stage and the loaded
+    ///   video is smaller, then the SWFMatrix is still an "identity
+    ///   matrix". However, if the video object is scaled via ActionScript,
+    ///   for example, then the SWFMatrix will change. This means the
+    ///   renderer has to find the correct scaling for the video inside the
+    ///   bounds.                                
+    ///
+    /// @param bounds The minX/minY fields of this rect are always zero. 
+    ///   The width and height determine the size of the Flash video instance
+    ///   on the stage (in TWIPS) prior to SWFMatrix transformations.         
+    ///
+    virtual void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat,
+            const rect* bounds, bool smooth) = 0;
+
+    /// Draw a line-strip directly, using a thin, solid line.
+    //
+    /// Can be used to draw empty boxes and cursors.
+    ///
+    /// @coords an array of 16-bit signed integer coordinates. Even indices
+    ///         (and 0) are x coordinates, while uneven ones are y coordinates.
+    ///
+    /// @vertex_count the number of x-y coordinates (vertices).
+    ///
+    /// @color the color to be used to draw the line strip.
+    ///
+    /// @mat the SWFMatrix to be used to transform the vertices.
+    virtual void draw_line_strip(const boost::int16_t* coords, int 
vertex_count,
+            const rgba& color, const SWFMatrix& mat) = 0;
+        
+    /// Draw a simple, solid filled polygon with a thin (~1 pixel) outline.
+    //
+    /// This can't be used for 
+    /// Flash shapes but is intended for internal drawings like bounding boxes 
+    /// (editable text fields) and similar. The polygon should not contain 
+    /// self-intersections. If you do not wish a outline or a fill, then 
simply 
+    /// set the alpha value to zero.
+    ///
+    /// The polygon need NOT be closed (ie: this function will automatically
+    /// add an additional vertex to close it.
+    ///
+    /// When masked==false, then any potential mask currently active will be
+    /// ignored, otherwise it is respected.
+    ///
+    virtual void draw_poly(const point* corners, size_t corner_count, 
+        const rgba& fill, const rgba& outline, const SWFMatrix& mat,
+        bool masked) = 0;
+        
+        
+    /// \brief
+    /// Draws the given character definition with the stateful properties
+    /// of the given instance.
+    //
+    /// Normally this does not need to be re-implemented in 
+    /// render handler implementations. Instead, see the version without
+    /// character instance.
+    ///
+    virtual void draw_shape_character(shape_character_def *def, 
+        character *inst)
+    {
+        // check if the character needs to be rendered at all
+        rect cur_bounds;
+
+        cur_bounds.expand_to_transformed_rect(inst->getWorldMatrix(), 
+                def->get_bound());
+                
+        if (!bounds_in_clipping_area(cur_bounds))
+        {
+                return; // no need to draw
+        }        
+
+        // TODO: I don't like that there is a draw_shape_character() version
+        // with arbitrary fill and line styles as this may break caching...
+
+        // render the character
+        draw_shape_character(def, 
+                inst->getWorldMatrix(), 
+                inst->get_world_cxform(),
+                def->get_fill_styles(),
+                def->get_line_styles());
+    }
+    
+    /// \brief
+    /// Draws the given character definition with the given transformations and
+    /// styles. 
+    virtual void draw_shape_character(shape_character_def *def, 
+        const SWFMatrix& mat,
+        const cxform& cx,
+        const std::vector<fill_style>& fill_styles,
+        const std::vector<line_style>& line_styles) = 0;
+        
+    /// \brief
+    /// Draws a glyph (font character).
+    //
+    /// Glyphs are defined just like shape characters with the difference that
+    /// they do not have any fill or line styles.
+    /// Instead, the shape must be drawn using the given color (solid fill).
+    /// Please note that although the glyph paths may indicate subshapes,
+    /// the renderer is to ignore that information.
+    /// 
+    /// @param def
+    ///
+    /// @param mat
+    ///
+    /// @param color
+    virtual void draw_glyph(shape_character_def *def, const SWFMatrix& mat,
+        const rgba& color) = 0;
+
+
+    /// ==================================================================
+    /// Prepare drawing area and other utilities
+    /// ==================================================================
+    
+    /// Sets the update region (called prior to begin_display).
+    //
+    /// The renderer 
+    /// might do clipping and leave the region outside these bounds unchanged,
+    /// but he is allowed to change them if that makes sense. After rendering
+    /// a frame the area outside the invalidated region can be undefined and 
+    /// is not used. 
+    ///
+    /// It is not required for all renderers.
+    /// Parameters are world coordinates (TWIPS).
+    ///
+    /// For more info see page \ref region_update.
+    ///
+    virtual void set_invalidated_region(const rect& /*bounds*/) {}
+
+    virtual void set_invalidated_regions(const InvalidatedRanges& /*ranges*/)
+    {        
+    }
+    
+    /// Bracket the displaying of a frame from a movie.
+    //
+    /// Set up to render a full frame from a movie and fills the
+    /// background. Sets up necessary transforms, to scale the
+    /// movie to fit within the given dimensions.    Call
+    /// end_display() when you're done.
+    ///
+    /// The rectangle (viewport_x0, viewport_y0, viewport_x0 +
+    /// viewport_width, viewport_y0 + viewport_height) defines the
+    /// window coordinates taken up by the movie.
+    ///
+    /// The rectangle (x0, y0, x1, y1) defines the pixel
+    /// coordinates of the movie that correspond to the viewport
+    /// bounds.
+    ///
+    virtual void begin_display(const rgba& background_color, int viewport_x0,
+                    int viewport_y0, int viewport_width, int viewport_height,
+                    float x0, float x1, float y0, float y1) = 0;
+
+    virtual void end_display() = 0;
+        
+    ///@{ Masks
+    ///
+    /// Masks are defined by drawing calls enclosed by begin_submit_mask()
+    /// and end_submit_mask(). Between these two calls, no drawing is to
+    /// occur. The shapes rendered between the two calls define the
+    /// visible region of the mask. Graphics that are irrelevant in the
+    /// context of a mask (lines and fill styles, for example) should be
+    /// ignored. After use, disable_mask() is called to remove the mask.
+    ///
+    /// Masks may be nested. That is, end_submit_mask() may be followed
+    /// by a call to begin_submit_mask(). The resulting mask shall be an
+    /// intersection of the previously created mask. disable_mask() shall
+    /// result in the disabling or destruction of the last created mask.
+    virtual void begin_submit_mask() = 0;
+    virtual void end_submit_mask() = 0;
+    virtual void disable_mask() = 0;
+    ///@}
+    
+    /// ==================================================================
+    /// Interface for querying the renderer.
+    /// ==================================================================
+    
+    /// Converts world coordinates to pixel coordinates
+    virtual geometry::Range2d<int> world_to_pixel(const rect& worldbounds) = 0;
+    
+    /// Converts pixel coordinates to world coordinates (TWIPS)
+    virtual point pixel_to_world(int x, int y) = 0;
+    
+    virtual geometry::Range2d<float> pixel_to_world(
+                    const geometry::Range2d<int>& pixelbounds)
+    {
+        point topleft = pixel_to_world(
+                        pixelbounds.getMinX(), pixelbounds.getMinY());
+        point bottomright = pixel_to_world(
+                        pixelbounds.getMaxX(), pixelbounds.getMaxY());
+        
+        return geometry::Range2d<float> (topleft.x, topleft.y, 
+            bottomright.x, bottomright.y);
+    }
+    
+    virtual geometry::Range2d<int> world_to_pixel(
+                    const geometry::Range2d<float>& worldbounds)
+    {
+        if ((worldbounds.isNull() || worldbounds.isWorld())) return 
worldbounds;
+
+        return world_to_pixel(rect(worldbounds.getMinX(),
+                    worldbounds.getMinY(), worldbounds.getMaxX(),
+                    worldbounds.getMaxY()));    
+    }
+    
+        
+    /// \brief
+    /// Checks if the given bounds are (partially) in the current drawing
+    /// clipping area.
+    //
+    /// A render handler implementing invalidated bounds should implement
+    /// this method to avoid rendering of characters that are not visible
+    /// anyway.
+    /// By default this method always returns true, which will ensure correct
+    /// rendering. If possible, it should be re-implemented by the renderer 
+    /// handler for better performance.
+    /// 'bounds' contains TWIPS coordinates.
+    ///
+    /// TODO: Take a Range2d<T> rather then a gnash::rect ?
+    ///             Would T==int be good ? TWIPS as integer types ?
+    ///
+    /// See also gnash::renderer::bounds_in_clipping_area
+    ///
+    virtual bool bounds_in_clipping_area(const rect& bounds) {
+        return bounds_in_clipping_area(bounds.getRange());
+    }
+    
+    virtual bool bounds_in_clipping_area(const InvalidatedRanges& ranges)
+    {
+        for (unsigned int rno=0; rno<ranges.size(); rno++) 
+        {
+            if (bounds_in_clipping_area(ranges.getRange(rno)))
+                return true;
+        }
+                
+        return false;
+    }
+    
+    virtual bool bounds_in_clipping_area(
+            const geometry::Range2d<float>& /*bounds*/)
+    {
+        return true;
+    }
+
+#ifdef USE_TESTSUITE
+
+    /// ==================================================================
+    /// Interfaces for testing only. Disabled when the testsuite isn't built.
+    /// ==================================================================
+
+
+    /// This function returns the color at any position in the stage. It is 
used
+    /// for automatic testing only, it should not be used for anything else!
+    /// x and y are pixel coordinates (<0 won't make any sense) and the color 
of 
+    /// the nearest pixel is returned.
+    /// The function returns false when the coordinates are outside the 
+    /// main frame buffer.
+    virtual bool getPixel(rgba& /*color_return*/, int /*x*/, int /*y*/)
+    {
+
+        log_debug("getPixel() not implemented for this renderer");
+        abort();        
+        return false; // avoid compiler warning        
+    }
+    
+    
+    /// Returns the average RGB color for a square block on the stage. The 
+    /// width and height of the block is defined by "radius" and x/y refer
+    /// to the center of the block. radius==1 equals getPixel() and radius==0
+    /// is illegal. For even "radius" values, the center point is not exactly
+    /// defined. 
+    /// The function returns false when at least one pixel of the block was
+    /// outside the main frame buffer. In that case the value in color_return
+    /// is undefined.
+    /// This implementation is provided for simplicity. Renderers should
+    /// implement a specialized version for better performance.
+    virtual bool getAveragePixel(rgba& color_return, int x, int y, 
+        unsigned int radius)
+    {
+    
+        assert(radius>0); 
+    
+        // optimization:
+        if (radius==1) return getPixel(color_return, x, y);
+    
+        unsigned int r=0, g=0, b=0, a=0;
+        
+        x -= radius/2;
+        y -= radius/2;
+        
+        int xe = x+radius;
+        int ye = y+radius;
+
+        rgba pixel;
+        
+        for (int yp=y; yp<ye; yp++)
+        for (int xp=x; xp<xe; xp++)
+        {
+            if (!getPixel(pixel, xp, yp))
+                return false;
+                
+            r += pixel.m_r;            
+            g += pixel.m_g;            
+            b += pixel.m_b;            
+            a += pixel.m_a;            
+        }
+        
+        int pcount = radius*radius; 
+        color_return.m_r = r / pcount; 
+        color_return.m_g = g / pcount; 
+        color_return.m_b = b / pcount; 
+        color_return.m_a = a / pcount; 
+        
+        return true;
+    }
+    
+    
+    /// \brief
+    /// Initializes the renderer for off-screen rendering used by the    
+    /// testsuite.
+    ///
+    /// This is a special function used for testcases ONLY. It is used by
+    /// MovieTester to prepare the renderer for off-screen rendering 
+    /// without any GUI. The renderer is responsible to do all required
+    /// steps so that rendering is possible after the call. This may mean
+    /// that the renderer allocates memory for the given stage size.
+    /// 
+    /// The function returns false when the renderer is not able to do
+    /// off-screen rendering (default).
+    ///
+    /// Note the function may be called again afterwards, resizing the stage.
+    /// Any number of calls to this function is possible and the renderer
+    /// is responsible to resize any buffer instead of wasting memory. 
+    ///
+    /// @param width stage width in pixels
+    ///
+    /// @param height stage height in pixels
+    virtual bool initTestBuffer(unsigned /*width*/, unsigned /*height*/)
+    {
+        return false;
+    }
+
+    /// Return color depth (bits per pixel) or 0 if unknown/unimplemented.
+    //
+    /// Default implementation returns 0 (unknown).
+    ///
+    /// TODO: this should be a pure abstract function, just don't want
+    ///     to scan ogl and cairo backend for an implementation *now*
+    ///     but would be needed for automated testing... Quinn, can you help ?
+    ///
+    virtual unsigned int getBitsPerPixel() const
+    {
+        return 0;
+    }
+    
+#endif
 
 protected:
 
-  /// Cached fill style list with just one entry used for font rendering
-  std::vector<fill_style> m_single_fill_styles;
-
-  /// Dummy line styles list without entries (do not add anything!!)
-  std::vector<line_style> m_dummy_line_styles;
-
-  /// Dummy, neutral color transformation (do not change!!)
-  cxform m_neutral_cxform;
-
-  /// Sets m_single_fill_styles to one solid fill with the given color 
-  void need_single_fill_style(const rgba& color)
-  {
-
-    if (m_single_fill_styles.size() == 0)
-    { 
-      fill_style dummy;
-      m_single_fill_styles.push_back(dummy);
-    }
-
-    m_single_fill_styles[0].set_color(color);
-
-  } 
+    /// Cached fill style list with just one entry used for font rendering
+    std::vector<fill_style> m_single_fill_styles;
+
+    /// Dummy line styles list without entries (do not add anything!!)
+    std::vector<line_style> m_dummy_line_styles;
+
+    /// Dummy, neutral color transformation (do not change!!)
+    cxform m_neutral_cxform;
+
+    /// Sets m_single_fill_styles to one solid fill with the given color 
+    void need_single_fill_style(const rgba& color)
+    {
+
+        if (m_single_fill_styles.size() == 0)
+        { 
+            fill_style dummy;
+            m_single_fill_styles.push_back(dummy);
+        }
+
+        m_single_fill_styles[0].set_color(color);
+
+    } 
+
+    /// Kept in parallel with movie_root's setting.
+    Quality _quality;
 
 }; // class render_handler
 

=== modified file 'backend/render_handler_agg.cpp'
--- a/backend/render_handler_agg.cpp    2009-01-09 00:32:29 +0000
+++ b/backend/render_handler_agg.cpp    2009-01-16 18:00:27 +0000
@@ -174,7 +174,7 @@
 #include "render_handler_agg_bitmap.h"
 #include "render_handler_agg_style.h"
 
-//#include <boost/foreach.hpp>
+#include <boost/scoped_array.hpp>
 
 #ifndef round
        #define round(x) rint(x)
@@ -262,81 +262,76 @@
 class agg_alpha_mask 
 {
 
-  typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base;
-  typedef agg::alpha_mask_gray8 amask_type;
+    typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base;
+    typedef agg::alpha_mask_gray8 amask_type;
 
 public:
 
-  agg_alpha_mask(int width, int height) :
-    m_rbuf(NULL, width, height, width),    // *
-    m_pixf(m_rbuf),
-    m_rbase(m_pixf),
-    m_amask(m_rbuf)
-  {
-  
-    // * = m_rbuf is first initialized with a NULL buffer so that m_pixf and
-    // m_rbase initialize with the correct buffer extents
-  
-    m_buffer = new boost::uint8_t[width*height];
-    
-    m_rbuf.attach(m_buffer, width, height, width);
-    
-    // NOTE: The buffer is *not* cleared. The clear() function must be called
-    // to clear the buffer (alpha=0). The reason is to avoid clearing the 
-    // whole mask when only a small portion is really used.
-
-  }
-  
-  ~agg_alpha_mask() 
-  {
-    delete [] m_buffer;
-  }
-  
-  void clear(const geometry::Range2d<int>& region)
-  {
-    if (region.isNull()) return;
-    assert ( region.isFinite() );
-
-    const agg::gray8 black(0);
+    agg_alpha_mask(int width, int height)
+        :
+        m_rbuf(0, width, height, width),
+        m_pixf(m_rbuf),
+        m_rbase(m_pixf),
+        m_amask(m_rbuf),
+        _buffer(new boost::uint8_t[width * height])
+    {
+        m_rbuf.attach(_buffer.get(), width, height, width);
         
-    // region can't be world as it should be intersected with 
-    // the visible rect
-    assert (! region.isWorld() );
-
-    unsigned int left=region.getMinX();
-    unsigned int width=region.width()+1;
-
-    const unsigned int max_y = region.getMaxY();
-          for (unsigned int y=region.getMinY(); y<=max_y; ++y) 
-    {
-       m_pixf.copy_hline(left, y, width, black);
-    }
-  }
-  
-  renderer_base& get_rbase() {
-    return m_rbase;
-  }
-  
-  amask_type& get_amask() {
-    return m_amask;
-  }  
-  
-  
+        // NOTE: The buffer is *not* cleared. The clear() function must
+        // be called to clear the buffer (alpha=0). The reason is to avoid
+        // clearing the whole mask when only a small portion is really used.
+    }
+    
+    ~agg_alpha_mask() 
+    {
+    }
+    
+    void clear(const geometry::Range2d<int>& region)
+    {
+        if (region.isNull()) return;
+        assert(region.isFinite());
+
+        const agg::gray8 black(0);
+                
+        // region can't be world as it should be intersected with 
+        // the visible rect
+        assert(!region.isWorld());
+
+        unsigned int left = region.getMinX();
+        unsigned int width = region.width() + 1;
+
+        const unsigned int max_y = region.getMaxY();
+        for (unsigned int y=region.getMinY(); y <= max_y; ++y) 
+        {
+             m_pixf.copy_hline(left, y, width, black);
+        }
+    }
+    
+    renderer_base& get_rbase() {
+        return m_rbase;
+    }
+    
+    amask_type& get_amask() {
+        return m_amask;
+    }    
+    
 private:
-  // in-memory buffer
-  boost::uint8_t* m_buffer;
-  
-  // agg class to access the buffer
-  agg::rendering_buffer m_rbuf;
-  
-  // pixel access
-  agg::pixfmt_gray8 m_pixf;  
-  
-  // renderer base
-  renderer_base m_rbase;
-  
-  // alpha mask
-  amask_type m_amask;
+
+    // agg class to access the buffer
+    agg::rendering_buffer m_rbuf;
+    
+    // pixel access
+    agg::pixfmt_gray8 m_pixf;    
+    
+    // renderer base
+    renderer_base m_rbase;
+    
+    // alpha mask
+    amask_type m_amask;
+    
+    // in-memory buffer
+    boost::scoped_array<boost::uint8_t> _buffer;
+    
 };
 
 
@@ -349,72 +344,143 @@
 template <class PixelFormat>
 class render_handler_agg : public render_handler_agg_base
 {
+  
+    typedef typename std::vector<geometry::Range2d<int> > ClipBounds;
+    typedef typename std::vector<agg_alpha_mask*>  AlphaMasks;
 private:
-  typedef agg::renderer_base<PixelFormat> renderer_base;
-
-  // renderer base
-  std::auto_ptr<renderer_base> m_rbase;
-  
-  typedef agg::conv_stroke< agg::conv_curve< agg::path_storage > > stroke_type;
-  
-  // TODO: Change these!!
-  unsigned char *memaddr;
-  int memsize;
-  int xres;
-  int yres;
-  int bpp;  // bits per pixel
-  // double xscale, yscale;  <-- deprecated, to be removed
-  gnash::SWFMatrix stage_matrix;  // conversion from TWIPS to pixels
-  bool scale_set;
-  
-  
-
-
+    typedef agg::renderer_base<PixelFormat> renderer_base;
+
+    // renderer base
+    std::auto_ptr<renderer_base> m_rbase;
+
+    typedef agg::conv_stroke< agg::conv_curve<agg::path_storage> > stroke_type;
+
+    // TODO: Change these!!
+    unsigned char *memaddr;
+    int memsize;
+    int xres;
+    int yres;
+    int bpp;  // bits per pixel
+    gnash::SWFMatrix stage_matrix;  // conversion from TWIPS to pixels
+    bool scale_set;
+
+
+    /// Class for rendering video frames.
+    //
+    /// Templated functions are used to allow using different types,
+    /// particularly for high and low quality rendering. 
+    //
+    /// At present, this is bound to the renderer's ClipBounds. In future it
+    /// may be useful to pass BlendMode, Cxform, and custom clipbounds as well
+    /// as a caller-provided rendering buffer. This also applies to the 
+    /// rest of the renderer API.
+    class VideoRenderer
+    {
+
+    public:
+
+        /// Fixed types for video frame rendering.
+        typedef agg::span_interpolator_linear<> Interpolator;
+        typedef agg::pixfmt_rgb24_pre BaseFormat;
+        typedef agg::span_allocator<agg::rgba8> SpanAllocator;
+        typedef agg::rasterizer_scanline_aa<> Rasterizer;
+        typedef agg::image_accessor_clone<BaseFormat> Accessor;
+
+        /// Types used for different quality.
+        //
+        /// This (affects scaling) should probably only be used when
+        /// Video.smoothing is true.
+        typedef typename agg::span_image_filter_rgb_nn<Accessor,
+                Interpolator> LowQualitySpanGenerator;
+
+        typedef typename agg::span_image_filter_rgb_bilinear<Accessor,
+                Interpolator> HighQualitySpanGenerator;
+
+        typedef agg::trans_affine Matrix;
+
+        VideoRenderer(const ClipBounds& clipbounds, GnashImage* frame,
+                Matrix& mat)
+            :
+            _buf(frame->data(), frame->width(), frame->height(),
+                    frame->pitch()),
+            _pixf(_buf),
+            _accessor(_pixf),
+            _interpolator(mat),
+            _clipbounds(clipbounds)
+        {}
+
+        /// Render a frame with or without alpha masks active.
+        template<typename SpanGenerator>
+        void
+        renderFrame(agg::path_storage& path, renderer_base& rbase,
+                const AlphaMasks& masks)
+        {
+            SpanGenerator sg(_accessor, _interpolator);
+            if (masks.empty()) {
+                // No mask active
+                agg::scanline_u8 sl;
+                renderScanlines(path, rbase, sl, sg);
+            }
+            else {
+                // Untested.
+                typedef agg::scanline_u8_am<agg::alpha_mask_gray8> Scanline;
+                Scanline sl(masks.back()->get_amask());
+                renderScanlines(path, rbase, sl, sg);
+            }
+        } 
+
+    private:
+
+        template<typename Scanline, typename SpanGenerator>
+        void renderScanlines(agg::path_storage& path, renderer_base& rbase,
+                Scanline& sc, SpanGenerator& sg)
+        {
+            for (ClipBounds::const_iterator i = _clipbounds.begin(),
+                e = _clipbounds.end(); i != e; ++i)
+            {
+
+                const ClipBounds::value_type& cb = *i;
+                apply_clip_box<Rasterizer> (_ras, cb);
+
+                // <Udo>: AFAIK add_path() rewinds the vertex list (clears
+                // previous path), so there should be no problem with
+                // multiple clipbounds.
+                _ras.add_path(path);
+
+                agg::render_scanlines_aa(_ras, sc, rbase, _sa, sg);
+            }
+        }
+        
+        // rendering buffer is used to access the frame pixels here        
+        agg::rendering_buffer _buf;
+        BaseFormat _pixf;
+        
+        // cloning image accessor is used to avoid disturbing pixels at
+        // the edges for rotated video. 
+        Accessor _accessor;
+             
+        Interpolator _interpolator;
+        
+        Rasterizer _ras;
+        SpanAllocator _sa;
+        const ClipBounds& _clipbounds;
+    };    
+                
 public:
 
-  // Enable/disable antialiasing.
-  bool  m_enable_antialias;
-
-  // Output size.
-  float m_display_width;
-  float m_display_height;
-
-  void set_antialiased(bool enable) {
-    // enable=false *forces* all bitmaps to be rendered in low quality
-    m_enable_antialias = enable;
-  }
-
-  // Style state.
-  enum style_index
-  {
-    LEFT_STYLE = 0,
-    RIGHT_STYLE,
-    LINE_STYLE,
-    STYLE_COUNT
-  };
-
-
-  gnash::BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im)
   // Given an image, returns a pointer to a bitmap_info class
   // that can later be passed to fill_styleX_bitmap(), to set a
   // bitmap fill style.
+  gnash::BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im)
   {    
     return new agg_bitmap_info(im);
   }
 
   void drawVideoFrame(GnashImage* frame, const SWFMatrix* source_mat, 
-    const rect* bounds) {
+    const rect* bounds, bool smooth) {
   
     // NOTE: Assuming that the source image is RGB 8:8:8
-    
-    // TODO: Currently only nearest-neighbor scaling is implemented here, since
-    // it's the fastest and Flash apparently uses this method most of the time.
-    // It would be easy to add other scaling methods (bilinear, bicubic, 
-    // whatever), but we'd need some way to tell the renderer the desired
-    // quality.
-    
     // TODO: keep heavy instances alive accross frames for performance!
-    
     // TODO: Maybe implement specialization for 1:1 scaled videos
     
     if (frame->type() == GNASH_IMAGE_RGBA)
@@ -422,8 +488,6 @@
         LOG_ONCE(log_error(_("Can't render videos with alpha")));
         return;
     }
-      
-    typedef agg::pixfmt_rgb24_pre baseformat;
 
     assert(frame->type() == GNASH_IMAGE_RGB);
     
@@ -431,52 +495,24 @@
     mat.concatenate(*source_mat);
     
     // compute video scaling relative to video obejct size
-    double vscaleX = TWIPS_TO_PIXELS(bounds->width())  / frame->width();
-    double vscaleY = TWIPS_TO_PIXELS(bounds->height()) / frame->height();
+    double vscaleX = bounds->width() / static_cast<double>(frame->width());
+    double vscaleY = bounds->height() / static_cast<double>(frame->height());
     
-    // convert Gnash SWFMatrix to AGG SWFMatrix and scale down to pixel 
coordinates
-    // while we're at it
-    agg::trans_affine img_mtx(
-      mat.sx  / 65536.0, mat.shx / 65536.0, 
-      mat.shy / 65536.0, mat.sy / 65536.0, 
-      mat.tx, mat.ty
-    );    
+    // convert Gnash SWFMatrix to AGG SWFMatrix and scale down to
+    // pixel coordinates while we're at it
+    agg::trans_affine img_mtx(mat.sx  / 65536.0, mat.shx / 65536.0, 
+      mat.shy / 65536.0, mat.sy / 65536.0, mat.tx, mat.ty);    
     
     // invert SWFMatrix since this is used for the image source
     img_mtx.invert();
     
-    // convert TWIPS to pixels and apply video scale
-    img_mtx *= agg::trans_affine_scaling(1.0/(20.0*vscaleX), 
1.0/(20.0*vscaleY));
-    
-    // span allocator is used to apply the SWFMatrix
-    agg::span_allocator<agg::rgba8> sa;
-        
-    typedef agg::span_interpolator_linear<> interpolator_type;
-    interpolator_type interpolator(img_mtx);
-    
-    // cloning image accessor is used to avoid disturbing pixels at the edges
-    // for rotated video. 
-    typedef agg::image_accessor_clone<baseformat> img_source_type;
-    
-    // rendering buffer is used to access the frame pixels here        
-    agg::rendering_buffer img_buf(frame->data(), frame->width(), 
frame->height(),
-      frame->pitch());
-         
-    baseformat img_pixf(img_buf);
-    
-    img_source_type img_src(img_pixf);
-    
-    // renderer base for the stage buffer (not the frame image!)
-    renderer_base& rbase = *m_rbase;
-        
-    // nearest neighbor method for scaling
-    typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type>
-      span_gen_type;
-    span_gen_type sg(img_src, interpolator);
-      
-    typedef agg::rasterizer_scanline_aa<> ras_type;
-    ras_type ras;
-    
+    // Apply video scale
+    img_mtx *= agg::trans_affine_scaling(1.0 / vscaleX, 1.0 / vscaleY);
+    
+    // TODO: keep this alive and only image / matrix? I've no idea how
+    // much reallocation that would save.
+    VideoRenderer vr(_clipbounds, frame, img_mtx);
+
     // make a path for the video outline
     point a, b, c, d;
     mat.transform(&a, point(bounds->get_x_min(), bounds->get_y_min()));
@@ -491,50 +527,21 @@
     path.line_to(d.x, d.y);
     path.line_to(a.x, a.y);
 
-    if (m_alpha_mask.empty()) {
-    
-      // No mask active
-
-      agg::scanline_u8 sl;
-  
-      for (unsigned int cno=0; cno<_clipbounds.size(); ++cno) {    
-      
-        const geometry::Range2d<int>& cbounds = _clipbounds[cno];
-        apply_clip_box<ras_type> (ras, cbounds);
-  
-        // <Udo>: AFAIK add_path() rewinds the vertex list (clears previous
-        // path), so there should be no problem with multiple clipbounds.      
-        ras.add_path(path);     
-           
-        agg::render_scanlines_aa(ras, sl, rbase, sa, sg);
-      }
-      
-    } else {
-    
-      // Mask is active!
-      
-      // **** UNTESTED!!! ****
-      
-      typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
-      scanline_type sl(m_alpha_mask.back()->get_amask());
-  
-      for (unsigned int cno=0; cno<_clipbounds.size(); ++cno) {    
-      
-        const geometry::Range2d<int>& cbounds = _clipbounds[cno];
-        apply_clip_box<ras_type> (ras, cbounds);
-  
-        // <Udo>: AFAIK add_path() rewinds the vertex list (clears previous
-        // path), so there should be no problem with multiple clipbounds.      
-        ras.add_path(path);     
-           
-        agg::render_scanlines_aa(ras, sl, rbase, sa, sg);
-      }
-      
-    
-    } // if alpha mask
-    
-  } // drawVideoFrame
-  
+    // renderer base for the stage buffer (not the frame image!)
+    renderer_base& rbase = *m_rbase;
+    
+    // If smoothing is requested and _quality is set to HIGH or BEST,
+    // use high-quality interpolation.
+    if (smooth && _quality >= QUALITY_HIGH) {
+        typedef typename VideoRenderer::HighQualitySpanGenerator HSG;
+        vr.template renderFrame<HSG>(path, rbase, m_alpha_mask);
+    }
+    else {
+        typedef typename VideoRenderer::LowQualitySpanGenerator LSG;
+        vr.template renderFrame<LSG>(path, rbase, m_alpha_mask);
+    }
+        
+  } 
 
   // Constructor
   render_handler_agg(int bits_per_pixel)
@@ -548,7 +555,6 @@
       /*xscale(1.0/20.0),
       yscale(1.0/20.0),*/
       scale_set(false),
-      m_enable_antialias(true),
       m_display_width(0.0),
       m_display_height(0.0),
       m_drawing_mask(false)
@@ -665,7 +671,7 @@
   }
 
   template <class ras_type>
-  void apply_clip_box(ras_type& ras, 
+  static void apply_clip_box(ras_type& ras, 
     const geometry::Range2d<int>& bounds)
   {
     assert(bounds.isFinite());
@@ -678,9 +684,9 @@
 
 
   
-  void  draw_line_strip(const boost::int16_t* coords, int vertex_count, const 
rgba& color,
-                  const SWFMatrix& line_mat)
   // Draw the line strip formed by the sequence of points.
+  void draw_line_strip(const boost::int16_t* coords, int vertex_count,
+          const rgba& color, const SWFMatrix& line_mat)
   {
     assert(m_pixf.get());
 
@@ -728,7 +734,7 @@
       
       for (unsigned int cno=0; cno<_clipbounds.size(); ++cno) {
       
-        const geometry::Range2d<int>& bounds = _clipbounds[cno];
+        const ClipBounds::value_type& bounds = _clipbounds[cno];
               
         apply_clip_box<ras_type> (ras, bounds);
         
@@ -752,7 +758,7 @@
       
       for (unsigned int cno=0; cno<_clipbounds.size(); ++cno) {
       
-        const geometry::Range2d<int>& bounds = _clipbounds[cno];
+        const ClipBounds::value_type& bounds = _clipbounds[cno];
               
         apply_clip_box<ras_type> (ras, bounds);
         
@@ -1312,8 +1318,9 @@
 
           sh.add_bitmap(dynamic_cast<agg_bitmap_info*> 
             (fill_styles[fno].get_bitmap_info()), m, cx, 
-            (fill_type==SWF::FILL_TILED_BITMAP) || 
(fill_type==SWF::FILL_TILED_BITMAP_HARD),
-            smooth && m_enable_antialias);
+            (fill_type==SWF::FILL_TILED_BITMAP) ||
+            (fill_type==SWF::FILL_TILED_BITMAP_HARD),
+            smooth && _quality <= QUALITY_MEDIUM);
           break;
         } 
 
@@ -1581,7 +1588,6 @@
     
     // now render that thing!
     agg::render_scanlines_compound_layered (rasc, sl, rbase, alloc, sh);
-    //agg::render_scanlines(rasc, sl, ren_sl);
         
   } // draw_mask_shape
 
@@ -1794,7 +1800,7 @@
     // iterate through clipping bounds
     for (unsigned int cno=0; cno<_clipbounds.size(); ++cno) {
     
-      const geometry::Range2d<int>& bounds = _clipbounds[cno];         
+      const ClipBounds::value_type& bounds = _clipbounds[cno];         
       apply_clip_box<ras_type> (ras, bounds);     
             
       
@@ -2012,19 +2018,23 @@
   
 private:  // private variables
 
+  // Output size.
+  float m_display_width;
+  float m_display_height;
+
   agg::rendering_buffer m_rbuf;  
 
   std::auto_ptr<PixelFormat> m_pixf;
   
   /// clipping rectangle
-  std::vector< geometry::Range2d<int> > _clipbounds;
+  ClipBounds _clipbounds;
   std::vector< geometry::Range2d<int>* > _clipbounds_selected;
   
   // this flag is set while a mask is drawn
   bool m_drawing_mask; 
   
   // Alpha mask stack
-  std::vector< agg_alpha_mask* > m_alpha_mask;
+  AlphaMasks m_alpha_mask;
 };  // end class render_handler_agg
 
 

=== modified file 'backend/render_handler_cairo.cpp'
--- a/backend/render_handler_cairo.cpp  2008-12-17 08:11:05 +0000
+++ b/backend/render_handler_cairo.cpp  2009-01-16 18:17:27 +0000
@@ -449,7 +449,8 @@
     }
   }
 
-  virtual void drawVideoFrame(GnashImage* baseframe, const SWFMatrix* m, const 
rect* bounds)
+  virtual void drawVideoFrame(GnashImage* baseframe, const SWFMatrix* m,
+          const rect* bounds, bool /*smooth*/)
   {
 
     if (baseframe->type() == GNASH_IMAGE_RGBA)

=== modified file 'backend/render_handler_ogl.cpp'
--- a/backend/render_handler_ogl.cpp    2008-12-17 08:19:34 +0000
+++ b/backend/render_handler_ogl.cpp    2009-01-16 18:17:27 +0000
@@ -505,7 +505,7 @@
 
 void
 bitmap_info_ogl::apply(const gnash::SWFMatrix& bitmap_matrix,
-                       render_handler::bitmap_wrap_mode wrap_mode)
+                       bitmap_wrap_mode wrap_mode)
 {
   glEnable(_ogl_img_type);
 
@@ -526,7 +526,7 @@
   
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   
-  if (wrap_mode == render_handler::WRAP_CLAMP) {  
+  if (wrap_mode == WRAP_CLAMP) {  
     glTexParameteri(_ogl_img_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(_ogl_img_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   } else {
@@ -659,7 +659,8 @@
   // anti-aliased with the rest of the drawing. Since display lists cannot be
   // concatenated this means we'll add up with several display lists for normal
   // drawing operations.
-  virtual void drawVideoFrame(GnashImage* frame, const SWFMatrix* m, const 
rect* bounds)
+  virtual void drawVideoFrame(GnashImage* frame, const SWFMatrix* m,
+          const rect* bounds, bool /*smooth*/)
   {
     GLint index;
 
@@ -1206,7 +1207,7 @@
           bitmap_info_ogl* binfo = 
static_cast<bitmap_info_ogl*>(style.need_gradient_bitmap());       
           SWFMatrix m = style.getGradientMatrix();
           
-          binfo->apply(m, render_handler::WRAP_CLAMP); 
+          binfo->apply(m, bitmap_info_ogl::WRAP_CLAMP); 
           
           break;
         }        
@@ -1215,7 +1216,7 @@
         {
           bitmap_info_ogl* binfo = 
static_cast<bitmap_info_ogl*>(style.get_bitmap_info());
 
-          binfo->apply(style.getBitmapMatrix(), render_handler::WRAP_REPEAT);
+          binfo->apply(style.getBitmapMatrix(), bitmap_info_ogl::WRAP_REPEAT);
           break;
         }
                 
@@ -1227,7 +1228,7 @@
           
           assert(binfo);
 
-          binfo->apply(style.getBitmapMatrix(), render_handler::WRAP_CLAMP);
+          binfo->apply(style.getBitmapMatrix(), bitmap_info_ogl::WRAP_CLAMP);
           
           break;
         } 
@@ -1695,6 +1696,7 @@
     
 
 private:
+  
   Tesselator _tesselator;
   float _xscale;
   float _yscale;

=== modified file 'backend/render_handler_ogl.h'
--- a/backend/render_handler_ogl.h      2008-12-16 15:15:55 +0000
+++ b/backend/render_handler_ogl.h      2009-01-16 16:55:03 +0000
@@ -148,12 +148,20 @@
 class bitmap_info_ogl : public BitmapInfo
 {
   public:
+  
+    /// Set line and fill styles for mesh & line_strip rendering.
+    enum bitmap_wrap_mode
+    {
+      WRAP_REPEAT,
+      WRAP_CLAMP
+    };
+    
     bitmap_info_ogl(GnashImage* image, GLenum pixelformat,
                     bool ogl_accessible);
     ~bitmap_info_ogl();
 
     void apply(const gnash::SWFMatrix& bitmap_matrix,
-               render_handler::bitmap_wrap_mode wrap_mode);
+               bitmap_wrap_mode wrap_mode);
   private:
     inline bool ogl_accessible() const;
     void setup();    

=== modified file 'cygnal/Makefile.am'
--- a/cygnal/Makefile.am        2008-11-06 19:58:35 +0000
+++ b/cygnal/Makefile.am        2009-01-16 16:13:37 +0000
@@ -55,6 +55,7 @@
         -I$(top_srcdir)/libbase \
         -I$(top_srcdir)/libmedia \
         -I$(top_srcdir)/libsound \
+        -I$(top_srcdir)/backend \
         -I$(top_srcdir)/libcore \
         -I$(top_srcdir)/libcore/asobj \
         -I$(top_srcdir)/libcore/parser \

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2009-01-13 13:35:10 +0000
+++ b/libcore/MovieClip.cpp     2009-01-16 16:24:25 +0000
@@ -5206,25 +5206,6 @@
     return as_value(ptr->get_movie_definition()->get_url());
 }
 
-as_value
-movieclip_highquality_getset(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        // We don't support quality settings
-        return as_value(true);
-    }
-    else // setter
-    {
-        LOG_ONCE( log_unimpl("MovieClip._highquality setting") );
-    }
-    return as_value();
-}
-
 // TODO: move this to character class, _focusrect seems a generic property
 as_value
 movieclip_focusrect_getset(const fn_call& fn)
@@ -5399,7 +5380,10 @@
     gettersetter = movieclip_url_getset;
     o.init_property(NSV::PROP_uURL, gettersetter, gettersetter);
 
-    gettersetter = movieclip_highquality_getset;
+    gettersetter = character::quality;
+    o.init_property(NSV::PROP_uQUALITY, gettersetter, gettersetter);
+    
+    gettersetter = character::highquality;
     o.init_property(NSV::PROP_uHIGHQUALITY, gettersetter, gettersetter);
 
     gettersetter = movieclip_focusrect_getset;

=== modified file 'libcore/Video.cpp'
--- a/libcore/Video.cpp 2009-01-07 09:55:08 +0000
+++ b/libcore/Video.cpp 2009-01-16 19:13:21 +0000
@@ -60,7 +60,8 @@
        _ns(0),
        _embeddedStream(m_def ? true : false),
        _lastDecodedVideoFrameNum(-1),
-       _lastDecodedVideoFrame()
+       _lastDecodedVideoFrame(),
+    _smoothing(false)
 {
 
        set_prototype(getVideoInterface(*this));
@@ -144,7 +145,7 @@
        GnashImage* img = getVideoFrame();
        if (img)
        {
-               gnash::render::drawVideoFrame(img, &m, &bounds);
+               gnash::render::drawVideoFrame(img, &m, &bounds, _smoothing);
        }
 
        clear_invalidated();
@@ -361,12 +362,16 @@
 void
 attachPrototypeProperties(as_object& proto)
 {
+    const int protect = as_prop_flags::dontDelete;
+    
+    proto.init_property("deblocking", &video_deblocking, &video_deblocking,
+            protect);
+    proto.init_property("smoothing", &video_smoothing, &video_smoothing,
+            protect);
+    
     const int flags = as_prop_flags::dontDelete |
         as_prop_flags::readOnly;
 
-    proto.init_property("deblocking", &video_deblocking, &video_deblocking,
-            flags);
-    proto.init_property("smoothing", &video_smoothing, &video_smoothing, 
flags);
     proto.init_property("height", &video_height, &video_height, flags);
     proto.init_property("width", &video_width, &video_width, flags);
 }
@@ -460,9 +465,13 @@
 video_smoothing(const fn_call& fn)
 {
        boost::intrusive_ptr<Video> video = ensureType<Video>(fn.this_ptr);
-    UNUSED(video);
-
-    log_unimpl("Video.smoothing");
+
+    if (!fn.nargs) return as_value(video->smoothing());
+
+    bool smooth = fn.arg(0).to_bool();
+
+    video->setSmoothing(smooth);
+
     return as_value();
 }
 

=== modified file 'libcore/Video.h'
--- a/libcore/Video.h   2008-11-26 13:59:04 +0000
+++ b/libcore/Video.h   2009-01-16 18:00:27 +0000
@@ -99,6 +99,12 @@
     /// vary during playback.
     int width() const;
 
+    /// Whether this Video object should request smoothing when scaled.
+    bool smoothing() const { return _smoothing; }
+
+    /// Set whether smoothing is required.
+    void setSmoothing(bool b) { _smoothing = b; }
+
 protected:
 
 #ifdef GNASH_USE_GC
@@ -136,6 +142,9 @@
 
        /// The decoder used to decode the video frames
        std::auto_ptr<media::VideoDecoder> _decoder;
+
+    /// Whether to request smoothing when the video is scaled
+    bool _smoothing;
 };
 
 void video_class_init(as_object& global);

=== modified file 'libcore/character.cpp'
--- a/libcore/character.cpp     2009-01-15 11:26:44 +0000
+++ b/libcore/character.cpp     2009-01-16 16:24:25 +0000
@@ -262,6 +262,95 @@
 //---------------------------------------------------------------------
 
 as_value
+character::quality(const fn_call& fn)
+{
+    boost::intrusive_ptr<character> ptr = ensureType<character>(fn.this_ptr);
+
+    movie_root& mr = ptr->getVM().getRoot();
+
+    if (!fn.nargs)
+    {
+        switch (mr.getQuality())
+        {
+            case render_handler::QUALITY_BEST:
+                return as_value("BEST");
+            case render_handler::QUALITY_HIGH:
+                return as_value("HIGH");
+            case render_handler::QUALITY_MEDIUM:
+                return as_value("MEDIUM");
+            case render_handler::QUALITY_LOW:
+                return as_value("LOW");
+        }
+    }
+
+    /// Setter
+
+    if (!fn.arg(0).is_string()) return as_value();
+
+    const std::string& q = fn.arg(0).to_string();
+
+    StringNoCaseEqual noCaseCompare;
+
+    if (noCaseCompare(q, "BEST")) mr.setQuality(render_handler::QUALITY_BEST);
+    else if (noCaseCompare(q, "HIGH")) {
+        mr.setQuality(render_handler::QUALITY_HIGH);
+    }
+    else if (noCaseCompare(q, "MEDIUM")) {
+        mr.setQuality(render_handler::QUALITY_MEDIUM);
+    }
+    else if (noCaseCompare(q, "LOW")) {
+            mr.setQuality(render_handler::QUALITY_LOW);
+    }
+
+    return as_value();
+}
+
+as_value
+character::highquality(const fn_call& fn)
+{
+    boost::intrusive_ptr<character> ptr = ensureType<character>(fn.this_ptr);
+
+    movie_root& mr = ptr->getVM().getRoot();
+    
+    if (!fn.nargs)
+    {
+        switch (mr.getQuality())
+        {
+            case render_handler::QUALITY_BEST:
+                return as_value(2.0);
+            case render_handler::QUALITY_HIGH:
+                return as_value(1.0);
+            case render_handler::QUALITY_MEDIUM:
+            case render_handler::QUALITY_LOW:
+                return as_value(0.0);
+        }
+    }
+    
+    double q = fn.arg(0).to_number();
+
+    if (q < 0) mr.setQuality(render_handler::QUALITY_HIGH);
+    else if (q > 2) mr.setQuality(render_handler::QUALITY_BEST);
+    else {
+        int i = static_cast<int>(q);
+        switch(i)
+        {
+            case 0:
+                mr.setQuality(render_handler::QUALITY_LOW);
+                break;
+            case 1:
+                mr.setQuality(render_handler::QUALITY_HIGH);
+                break;
+            case 2:
+                mr.setQuality(render_handler::QUALITY_BEST);
+                break;
+        }
+    }
+
+    return as_value();
+}
+
+
+as_value
 character::x_getset(const fn_call& fn)
 {
        boost::intrusive_ptr<character> ptr = 
ensureType<character>(fn.this_ptr);

=== modified file 'libcore/character.h'
--- a/libcore/character.h       2009-01-14 08:50:47 +0000
+++ b/libcore/character.h       2009-01-16 16:24:25 +0000
@@ -1004,8 +1004,13 @@
   /// Default is a no-op. TextField implements this function.
   virtual void killFocus() {}
 
-  // TODO: make protected:
-
+  /// Getter-setter for _highquality.
+  static as_value highquality(const fn_call& fn);
+
+  /// Getter-setter for _quality.
+  static as_value quality(const fn_call& fn);
+
+  /// Getter-setter for blendMode.
   static as_value blendMode(const fn_call& fn);
 
   /// Getter-setter for _x

=== modified file 'libcore/movie_root.cpp'
--- a/libcore/movie_root.cpp    2009-01-13 07:05:59 +0000
+++ b/libcore/movie_root.cpp    2009-01-16 16:13:37 +0000
@@ -127,6 +127,8 @@
        _movieAdvancementDelay(83), // ~12 fps by default
        _lastMovieAdvancement(0)
 {
+    // This takes care of informing the renderer (if present) too.
+    setQuality(render_handler::QUALITY_HIGH);
 }
 
 void
@@ -1433,6 +1435,14 @@
     }
 }
 
+void
+movie_root::setQuality(render_handler::Quality q)
+{
+    _quality = q;
+    render_handler* renderer = get_render_handler();
+    if (renderer) renderer->setQuality(_quality);
+}
+
 /// Get actionscript width of stage, in pixels. The width
 /// returned depends on the scale mode.
 unsigned int

=== modified file 'libcore/movie_root.h'
--- a/libcore/movie_root.h      2008-12-03 08:22:34 +0000
+++ b/libcore/movie_root.h      2009-01-16 16:13:37 +0000
@@ -79,6 +79,7 @@
 #include "GnashKey.h" // key::code
 #include "movie_instance.h"
 #include "RunInfo.h" // for initialization
+#include "render_handler.h"
 
 #ifdef USE_SWFTREE
 # include "tree.hh"
@@ -508,6 +509,12 @@
         STAGE_ALIGN_B
     };
 
+    /// Set the current display quality of the entire SWF.
+    void setQuality(render_handler::Quality q);
+
+    /// Get the current display quality.
+    render_handler::Quality getQuality() const { return _quality; }
+
     /// Sets movie_root's horizontal and vertical alignment to one
     /// of the three possible positions for each dimension.
     void setStageAlignment(short s);
@@ -1128,7 +1135,13 @@
     //
     /// -1 if none
     int _hostfd;
-    
+
+    /// The display quality of the entire movie.
+    //
+    /// This is here, not just in the render_handler, so that AS compatibility
+    /// does not rely on the presence of a renderer.
+    render_handler::Quality _quality;
+
     std::bitset<4u> _alignMode;
     
     ScaleMode _scaleMode;

=== modified file 'libcore/render.cpp'
--- a/libcore/render.cpp        2008-12-17 07:54:39 +0000
+++ b/libcore/render.cpp        2009-01-16 18:00:27 +0000
@@ -87,8 +87,12 @@
        }
 
        // Draws the video frames
-       void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat, const 
rect* bounds){
-               if (s_render_handler) return 
s_render_handler->drawVideoFrame(frame, mat, bounds);
+       void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat,
+            const rect* bounds, bool smooth)
+    {
+               if (s_render_handler) {
+            return s_render_handler->drawVideoFrame(frame, mat, bounds, 
smooth);
+        }
        }
 
 

=== modified file 'libcore/render.h'
--- a/libcore/render.h  2008-12-16 15:15:55 +0000
+++ b/libcore/render.h  2009-01-16 18:00:27 +0000
@@ -57,7 +57,8 @@
                BitmapInfo* createBitmapInfo(std::auto_ptr<GnashImage> im);
 
                /// See render_handler::drawVideoFrame (in 
backend/render_handler.h)
-               void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat, 
const rect* bounds);
+               void drawVideoFrame(GnashImage* frame, const SWFMatrix* mat,
+                const rect* bounds, bool smooth);
 
                /// See render_handler::begin_display (in 
backend/render_handler.h)
                void    begin_display(

=== modified file 'testsuite/actionscript.all/MovieClip.as'
--- a/testsuite/actionscript.all/MovieClip.as   2009-01-15 11:26:44 +0000
+++ b/testsuite/actionscript.all/MovieClip.as   2009-01-16 16:13:37 +0000
@@ -115,15 +115,15 @@
 #endif
 
 #if OUTPUT_VERSION == 6
-       check_totals(829); // SWF6
+       check_totals(884); // SWF6
 #endif
 
 #if OUTPUT_VERSION == 7
-       check_totals(846); // SWF7
+       check_totals(901); // SWF7
 #endif
 
 #if OUTPUT_VERSION >= 8
-       check_totals(938); // SWF8+
+       check_totals(993); // SWF8+
 #endif
 
        play();
@@ -2212,6 +2212,94 @@
 
 #endif
 
+#if OUTPUT_VERSION > 5
+
+r = createEmptyMovieClip("r", getNextHighestDepth());
+check_equals(typeof(r._highquality), "number");
+check_equals(r._highquality, 1);
+r._highquality = 1;
+check_equals(r._quality, "HIGH");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+
+r._highquality = 3;
+check_equals(r._quality, "BEST");
+check_equals(r._highquality, 2);
+check_equals(_root._highquality, 2);
+
+r._highquality = "1";
+check_equals(r._quality, "HIGH");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+
+r._highquality = false;
+check_equals(r._quality, "LOW");
+check_equals(typeof(r._highquality), "number");
+check_equals(r._highquality, 0);
+check_equals(_root._highquality, 0);
+
+r._highquality = 0;
+check_equals(r._quality, "LOW");
+check_equals(typeof(r._highquality), "number");
+check_equals(r._highquality, 0);
+check_equals(_root._highquality, 0);
+
+r._highquality = -1;
+check_equals(r._quality, "HIGH");
+check_equals(typeof(r._highquality), "number");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+
+r._highquality = -2;
+check_equals(r._quality, "HIGH");
+check_equals(typeof(r._highquality), "number");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+
+/// Test setting _quality
+
+r._quality = "MEDIUM";
+check_equals(r._quality, "MEDIUM");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 0);
+check_equals(_root._highquality, 0);
+
+r._quality = "HIGH";
+check_equals(r._quality, "HIGH");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+
+r._quality = "BEST";
+check_equals(r._quality, "BEST");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 2);
+check_equals(_root._highquality, 2);
+
+r._quality = 1;
+check_equals(r._quality, "BEST");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 2);
+check_equals(_root._highquality, 2);
+
+r._quality = false;
+check_equals(r._quality, "BEST");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 2);
+check_equals(_root._highquality, 2);
+
+r._quality = "lOW";
+check_equals(r._quality, "LOW");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 0);
+check_equals(_root._highquality, 0);
+
+r._quality = "high";
+check_equals(r._quality, "HIGH");
+check_equals(typeof(r._quality), "string");
+check_equals(r._highquality, 1);
+check_equals(_root._highquality, 1);
+#endif 
 //_root.loadVariables(MEDIA(vars.txt), "GET");
 
 // Can't rely on this to call onData!

=== modified file 'testsuite/libcore.all/Makefile.am'
--- a/testsuite/libcore.all/Makefile.am 2008-09-03 21:46:17 +0000
+++ b/testsuite/libcore.all/Makefile.am 2009-01-16 16:30:00 +0000
@@ -20,6 +20,7 @@
 
 AM_CPPFLAGS = \
         -I$(top_srcdir)/testsuite  \
+        -I$(top_srcdir)/backend  \
         -I$(top_srcdir)/libamf  \
         -I$(top_srcdir)/libnet  \
         -I$(top_srcdir)/libbase  \

=== modified file 'utilities/Makefile.am'
--- a/utilities/Makefile.am     2008-11-29 20:25:32 +0000
+++ b/utilities/Makefile.am     2009-01-16 16:13:37 +0000
@@ -51,6 +51,7 @@
         -I$(top_srcdir)/libbase \
         -I$(top_srcdir)/libnet \
         -I$(top_srcdir)/libamf \
+        -I$(top_srcdir)/backend \
         -I$(top_srcdir)/libcore \
         -I$(top_srcdir)/libcore/asobj \
         -I$(top_srcdir)/libcore/parser \


reply via email to

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