gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash backend/render_handler_cairo.cpp backend/...


From: Bastiaan Jacques
Subject: [Gnash-commit] gnash backend/render_handler_cairo.cpp backend/...
Date: Thu, 18 Oct 2007 09:05:40 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Bastiaan Jacques <bjacques>     07/10/18 09:05:40

Modified files:
        backend        : render_handler_cairo.cpp render_handler_cairo.h 
        gui            : gtk_glue_cairo.cpp gtk_glue_cairo.h 

Log message:
                * backend/render_handler_cairo.cpp: New Cairo implementation.
                Fixes all Cairo bugs currently in Savannah, but adds a set of
                new bugs. The new renderer offers significantly better
                performance and better rendering quality. This implementation
                does not rely on Gnash's own triangulation.
                * backend/render_handler_cairo.h: Renamed set_handle to
                set_context, which is more descriptive.
                * gui/gtk_glue_cairo.{cpp,h}: Updated for set_context.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_cairo.cpp?cvsroot=gnash&r1=1.24&r2=1.25
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_cairo.h?cvsroot=gnash&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk_glue_cairo.cpp?cvsroot=gnash&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk_glue_cairo.h?cvsroot=gnash&r1=1.12&r2=1.13

Patches:
Index: backend/render_handler_cairo.cpp
===================================================================
RCS file: /sources/gnash/gnash/backend/render_handler_cairo.cpp,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -b -r1.24 -r1.25
--- backend/render_handler_cairo.cpp    10 Sep 2007 16:53:29 -0000      1.24
+++ backend/render_handler_cairo.cpp    18 Oct 2007 09:05:40 -0000      1.25
@@ -1,28 +1,55 @@
-// render_handler_cairo.cpp    -- Timothy Lee <address@hidden> 2006
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// A render_handler that uses cairo
-
+// 
+//   Copyright (C) 2005, 2006, 2007 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
+
+// Known bugs:
+// - Shape filling problems: renderer skips certain fills. See car_smash.swf.
+// - Fonts: The "a" is not filled in text-test.swf. If subshapes are ignored
+//          then it works as expected. The Agg renderer would suggest this has
+//          something to do with the fill rule.
+// - Rotation problem in gradient-tests.swf.
+//
+// TODOs:
+// - Implement focal gradients.
+// - Implement alpha bitmaps.
+// - Implement unimplemented methods.
+// - Would be nice to have a header/implementation separation.
+// - Document workings of Cairo and this renderer.
+// - Implement getPixel and friends.
+// - Test bitmap implementation correctness.
+// - Figure out what extend types should be used and when.
+// - Figure out what the deal with subpixel offsets is.
+// - Cleanups.
+// - Optimizations.
+//
+// Already implemented:
+// - outlines
+// - fills: solid, linear, radial and bitmap
+// - bitmaps (excluding alpha)
+// - fonts
+// - masks
+// - video (from old Cairo renderer)
 
 #include <cairo/cairo.h>
+#include <boost/scoped_array.hpp>
 #include "render_handler.h"
-#include "render_handler_tri.h"
-#include "types.h"
 #include "image.h"
-#include "utility.h"
-
-#include "tu_config.h"
-#include "log.h"
-
 
 namespace gnash {
-namespace renderer {
-namespace cairo {
 
-static cairo_t* g_cr_output = 0;
-static cairo_t* g_cr = 0;
 
 
 // Converts from RGB image to 32-bit pixels in CAIRO_FORMAT_RGB24 format
@@ -35,16 +62,14 @@
        const uint8_t* src = im->scanline(y);
        for (size_t x = 0;  x < im->width();  x++, src += 3)
        {
-           // 32-bit RGB data in native endian format
            *dst32++ = (src[0] << 16) | (src[1] << 8) | src[2];
        }
     }
 }
 
-
 // Converts from RGBA image to 32-bit pixels in CAIRO_FORMAT_ARGB32 format
 static void
-rgba_to_cairo_argb32(uint8_t* dst, const image::rgba* im)
+rgba_to_cairo_argb(uint8_t* dst, const image::rgba* im)
 {
     uint32_t* dst32 = reinterpret_cast<uint32_t*>(dst);
     for (size_t y = 0;  y < im->height();  y++)
@@ -52,706 +77,812 @@
        const uint8_t* src = im->scanline(y);
        for (size_t x = 0;  x < im->width();  x++, src += 4)
        {
-           // 32-bit ARGB data in native endian format
-           *dst32++ = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+      const uint8_t& r = src[0],
+                     g = src[1],
+                     b = src[2],
+                     a = src[3];
+      
+      if (a) {  
+        *dst32++ = (a << 24) | (r << 16) | (g << 8) | b;       
+      } else {
+        *dst32++ = 0;
+      }
        }
     }
 }
 
 
-// bitmap_info_cairo declaration
-class bitmap_info_cairo : public gnash::bitmap_info
+
+class bitmap_info_cairo : public bitmap_info
 {
-public:
-    // Cairo image surface
-    unsigned char*   m_buffer;
-    cairo_surface_t* m_image;
-    cairo_pattern_t* m_pattern;
-
-    bitmap_info_cairo();
-    bitmap_info_cairo(int width, int height, uint8_t* data);
-    bitmap_info_cairo(image::rgb* im);
-    bitmap_info_cairo(image::rgba* im);
-
-    ~bitmap_info_cairo() {
-       if (m_pattern)
-           cairo_pattern_destroy(m_pattern);
-       if (m_image)  cairo_surface_destroy(m_image);
-       if (m_buffer)  delete [] m_buffer;
+  public:
+    bitmap_info_cairo(uint8_t* data, int width, int height,
+                           size_t bpp, cairo_format_t format)
+    : _data(data),
+      _width(width),
+      _height(height),
+      _bytes_per_pixel(bpp),
+      _format(format),
+      _surface(cairo_image_surface_create_for_data(_data.get(),
+               format, width, height, width * bpp)),
+      _pattern(cairo_pattern_create_for_surface (_surface))
+    {
     }
+    
+    ~bitmap_info_cairo()
+    {
+      cairo_surface_destroy(_surface);
+    }
+    
+    cairo_pattern_t* apply(const cairo_matrix_t* mat, int fill_type)
+    {         
+      cairo_pattern_set_matrix(_pattern, mat);
+      
+      cairo_extend_t extend = CAIRO_EXTEND_REPEAT;
+
+#if 0
+      // The extend type should probably depend on certain factors, but which?
+      switch(fill_type) {
+        case SWF::FILL_CLIPPED_BITMAP:
+          break;
+        case SWF::FILL_CLIPPED_BITMAP_HARD:
+        case SWF::FILL_TILED_BITMAP_HARD:
+          break;
+        case SWF::FILL_TILED_BITMAP:
+          break;
+      }
+#endif
+    
+      cairo_pattern_set_extend(_pattern, extend);
+      
+      return _pattern;
+    }
+   
+  private:
+    boost::scoped_array<uint8_t> _data;
+    int _width;
+    int _height;
+    size_t _bytes_per_pixel;
+    cairo_format_t _format;
+    cairo_surface_t* _surface;
+    cairo_pattern_t* _pattern;
 };
 
 
-class render_handler_cairo : public gnash::triangulating_render_handler
+
+class DSOEXPORT render_handler_cairo: public render_handler
 {
+  typedef std::vector<path> PathVec;
+  typedef std::vector<const path*> PathPtrVec;
 public:
-    // Some renderer state.
-    cairo_t*         m_cr_mask;
-    cairo_t*    m_cr_dummy;
-    int              m_view_width;
-    int              m_view_height;
-    
-    // Video buffer
-    uint8_t*    m_video_buffer;
-    int                m_video_bufsize;
-    
-    // Enable/disable antialiasing.
-    bool       m_enable_antialias;
-    
-    // Output size.
-    float      m_display_width;
-    float      m_display_height;
-       
-    gnash::matrix      m_current_matrix;
-    gnash::cxform      m_current_cxform;
-    void set_antialiased(bool enable) {
-       m_enable_antialias = enable;
-    }
     
-    class fill_style
+  render_handler_cairo()
+    : _video_bufsize(0),
+      _drawing_mask(false)
     {
-    public:
-       enum mode
-       {
-           INVALID,
-           COLOR,
-           BITMAP_WRAP,
-           BITMAP_CLAMP,
-           LINEAR_GRADIENT,
-           RADIAL_GRADIENT
-       };
-       mode    m_mode;
-       gnash::rgba     m_color;
-       const bitmap_info_cairo*    m_bitmap_info;
-       gnash::matrix   m_bitmap_matrix;
-       gnash::cxform   m_bitmap_color_transform;
-       bool    m_has_nonzero_bitmap_additive_color;
+       cairo_surface_t* dummy_surface = cairo_image_surface_create(
+                                            CAIRO_FORMAT_A8, 1, 1);
+         _cr = cairo_create(dummy_surface);
+         cairo_surface_destroy(dummy_surface);
+  }
                
-       fill_style()
-           :
-           m_mode(INVALID),
-           m_has_nonzero_bitmap_additive_color(false)
+  ~render_handler_cairo()
            {
            }
 
-       // Push our style into cairo.
-       void apply(/*const matrix& current_matrix*/) const
-       {
-           assert(m_mode != INVALID);
            
-           if (m_mode == COLOR)
+  virtual bitmap_info*  create_bitmap_info_alpha(int w, int h, unsigned char* 
data)
            {
-               apply_color(m_color);
+    log_unimpl("create_bitmap_info_alpha");
+    return NULL;
            }
-           else if (m_mode == BITMAP_WRAP || m_mode == BITMAP_CLAMP)
+
+  virtual bitmap_info*  create_bitmap_info_rgb(image::rgb* im) 
            {
-               assert(m_bitmap_info != NULL);
+    int buf_size = im->width() * im->height() * 4;
+    uint8_t* buffer = new uint8_t[buf_size];
                
-               apply_color(m_color);
+    rgb_to_cairo_rgb24(buffer, im);
                
-               if (m_bitmap_info != NULL)
-               {
-                   // Set up the texture for rendering.
-                   {
-                       // Do the modulate part of the color
-                       // transform in the first pass.  The
-                       // additive part, if any, needs to
-                       // happen in a second pass.
-                       // FIXME!!! bitmap cannot be modulated by RGB
-                       cairo_set_source_rgba(g_cr,
-                           m_bitmap_color_transform.m_[0][0],
-                           m_bitmap_color_transform.m_[1][0],
-                           m_bitmap_color_transform.m_[2][0],
-                           m_bitmap_color_transform.m_[3][0]);
+    return new bitmap_info_cairo(buffer, im->width(), im->height(), 4,
+                                 CAIRO_FORMAT_RGB24);
                    }
                    
-                   cairo_pattern_t* pattern = m_bitmap_info->m_pattern;
+  virtual bitmap_info*  create_bitmap_info_rgba(image::rgba* im)
+  {        
+    int buf_size = im->width() * im->height() * 4;
+    uint8_t* buffer = new uint8_t[buf_size];
                    
-                   if (m_mode == BITMAP_CLAMP)
+    rgba_to_cairo_argb(buffer, im);
+    
+    return new bitmap_info_cairo(buffer, im->width(), im->height(), 4,
+                                 CAIRO_FORMAT_ARGB32);
+  }
+
+  virtual void  delete_bitmap_info(bitmap_info* bi)
                    {   
-                       cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
+    delete bi;
                    }
-                   else
+
+  virtual int videoFrameFormat()
                    {
-                       cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+    return render_handler::RGB;
                    }
                    
-                   // Set up the bitmap matrix
-                   // FIXME!!! scaling and offset is wrong
+  virtual void drawVideoFrame(image::image_base* baseframe, const matrix* m, 
const rect* bounds)
+  {
+    // Extract frame attributes
+    image::rgb* frame = static_cast<image::rgb*>(baseframe);
+    int         w = frame->width();
+    int         h = frame->height();
+
+    // Compute bounding rectangle size relative to video object
+    double w_scale = bounds->width() / w;
+    double h_scale = bounds->height() / h;
+
+    // Fit video to bounding rectangle
                    cairo_matrix_t mat;
-                   const gnash::matrix& m = m_bitmap_matrix;
-                   cairo_matrix_init(&mat, m.m_[0][0], m.m_[1][0],
-                       m.m_[0][1], m.m_[1][1], m.m_[0][2], m.m_[1][2]);
-                   cairo_pattern_set_matrix(pattern, &mat);
+    cairo_matrix_init_scale(&mat, w_scale, h_scale);
+    cairo_matrix_translate(&mat,
+           bounds->get_x_min(), bounds->get_y_min());
 
-                   cairo_set_source(g_cr, pattern);
-               }
+    // Now apply transformation to video
+    cairo_matrix_t frame_mat;
+    init_cairo_matrix(&frame_mat, *m);
+
+    cairo_matrix_multiply(&mat, &mat, &frame_mat);
+
+    // Inverse the matrix for pattern space
+    cairo_matrix_invert(&mat);
+
+    // Convert RGB frame to cairo format
+    size_t buf_size = w * h * 4;
+    
+    if (_video_bufsize < buf_size) {
+      _video_buffer.reset(new uint8_t[buf_size]);
+           _video_bufsize = buf_size;
            }
+    
+    rgb_to_cairo_rgb24(_video_buffer.get(), frame);
+
+    // Create a pattern from the the RGB frame
+    cairo_surface_t* surface = cairo_image_surface_create_for_data(
+           _video_buffer.get(), CAIRO_FORMAT_RGB24, w, h, w * 4);
+    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
+    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
+    cairo_pattern_set_matrix(pattern, &mat);
+
+    // Draw the frame now
+    cairo_save(_cr);
+    cairo_set_source(_cr, pattern);
+    
+    geometry::Range2d<float> range = bounds->getRange();
+         m->transform(range);
+         
+         cairo_rectangle(_cr, range.getMinX(), range.getMinY(), range.width(),
+                              range.height());
+    cairo_clip(_cr);
+    cairo_paint(_cr);
+    cairo_restore(_cr);
+
+    // Clean up
+    cairo_pattern_destroy(pattern);
+    cairo_surface_destroy(surface);
        }
        
        
-       // Return true if we need to do a second pass to make
-       // a valid color.  This is for cxforms with additive
-       // parts; this is the simplest way (that we know of)
-       // to implement an additive color with stock OpenGL.
-       bool    needs_second_pass() const
-           {
-               if (m_mode == BITMAP_WRAP || m_mode == BITMAP_CLAMP)
+  // FIXME
+  geometry::Range2d<int>
+  world_to_pixel(const rect& worldbounds)
+{
+  // TODO: verify this is correct
+  geometry::Range2d<int> ret(worldbounds.getRange());
+  ret.scale(1.0/20.0); // twips to pixels
+  return ret;
+}
+
+  // FIXME
+  point 
+  pixel_to_world(int x, int y)
                {
-                   return m_has_nonzero_bitmap_additive_color;
+    // TODO: verify this is correct
+    return point(PIXELS_TO_TWIPS(x), PIXELS_TO_TWIPS(y));
                }
-               else
+  
+  void
+  set_color(const rgba& c)
                {
-                   return false;
-               }
+    cairo_set_source_rgba (_cr, c.m_r / 255.0, c.m_g / 255.0,
+                                c.m_b / 255.0, c.m_a / 255.0);
            }
        
-       // Set OpenGL state for a necessary second pass.
-       void    apply_second_pass() const
+  virtual void  begin_display(
+    const rgba& bg_color,
+    int viewport_x0, int viewport_y0,
+    int viewport_width, int viewport_height,
+    float x0, float x1, float y0, float y1)
            {
-               assert(needs_second_pass());
                
-               // The additive color also seems to be modulated by the 
texture. So,
-               // maybe we can fake this in one pass using using the mean 
value of 
-               // the colors: c0*t+c1*t = ((c0+c1)/2) * t*2
-               // I don't know what the alpha component of the color is for.
                
-               cairo_set_source_rgba(g_cr,
-                   m_bitmap_color_transform.m_[0][1] / 255.0f,
-                   m_bitmap_color_transform.m_[1][1] / 255.0f,
-                   m_bitmap_color_transform.m_[2][1] / 255.0f,
-                   m_bitmap_color_transform.m_[3][1] / 255.0f);
+    float display_width  = fabsf(x1 - x0);
+    float display_height = fabsf(y1 - y0);
+
+    cairo_identity_matrix(_cr);
+    cairo_rectangle(_cr, x0, y0, display_width, display_height);
+    cairo_clip(_cr);
+    cairo_scale(_cr, viewport_width / display_width,
+                     viewport_height / display_height);
+    cairo_translate(_cr, x0, y0);
                
-/*
-               glBlendFunc(GL_ONE, GL_ONE);
-*/
+         // Clear the background, if background color has alpha > 0.
+         if (bg_color.m_a) {
+      set_color(bg_color);
+      cairo_paint(_cr);
+    }
            }
 
-       void    cleanup_second_pass() const
+  virtual void  end_display()
            {
-/*
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-*/
            }
 
+  virtual void  set_matrix(const matrix& m)
+  {
+    log_unimpl("set_matrix");
+  }
 
-       void    disable()  { m_mode = INVALID; }
-       void    set_color(const gnash::rgba& color)  { m_mode = COLOR; m_color 
= color; }
-       void    set_bitmap(const gnash::bitmap_info* bi, const gnash::matrix& 
m, bitmap_wrap_mode wm, const gnash::cxform& color_transform)
+  virtual void  set_cxform(const cxform& cx)
            {
-               m_mode = (wm == WRAP_REPEAT) ? BITMAP_WRAP : BITMAP_CLAMP;
-               m_bitmap_info = static_cast<const bitmap_info_cairo*>(bi);
-               m_bitmap_matrix = m;
-               m_bitmap_color_transform = color_transform;
-               m_bitmap_color_transform.clamp();
+    log_unimpl("set_cxform");
+  }
                        
-               m_color = gnash::rgba(
-                   uint8_t(m_bitmap_color_transform.m_[0][0] * 255.0f),
-                   uint8_t(m_bitmap_color_transform.m_[1][0] * 255.0f),
-                   uint8_t(m_bitmap_color_transform.m_[2][0] * 255.0f),
-                   uint8_t(m_bitmap_color_transform.m_[3][0] * 255.0f));
+  virtual void  draw_line_strip(const void* coords, int vertex_count,
+      const rgba& color)
+  {
+    log_unimpl("draw_line_strip");
+  }
                        
-               if (m_bitmap_color_transform.m_[0][1] > 1.0f
-                   || m_bitmap_color_transform.m_[1][1] > 1.0f
-                   || m_bitmap_color_transform.m_[2][1] > 1.0f
-                   || m_bitmap_color_transform.m_[3][1] > 1.0f)
+  virtual void  draw_poly(const point* corners, size_t corner_count, 
+    const rgba& fill, const rgba& outline, bool masked)
                    {
-                       m_has_nonzero_bitmap_additive_color = true;
+    log_unimpl("draw_poly");
                    }
-               else
+  
+  virtual void  draw_bitmap(
+    const matrix&   m,
+    const bitmap_info*  bi,
+    const rect&   coords,
+    const rect&   uv_coords,
+    const rgba&   color)
                    {
-                       m_has_nonzero_bitmap_additive_color = false;
+    log_unimpl("draw_bitmap");
                    }
+    
+  virtual void  set_antialiased(bool enable)
+  {
+    log_unimpl("set_antialiased");
            }
-       bool    is_valid() const { return m_mode != INVALID; }
-    };
 
+  virtual void begin_submit_mask()
+  {
+    PathVec mask;
+    _masks.push_back(mask);
+    
+    _drawing_mask = true;
+  }
 
-    // Style state.
-    enum style_index
+  virtual void end_submit_mask()
     {
-       LEFT_STYLE = 0,
-       RIGHT_STYLE,
-       LINE_STYLE,
+    _drawing_mask = false;
 
-       STYLE_COUNT
-    };
-    fill_style m_current_styles[STYLE_COUNT];
 
+    // Load the mask paths into the cairo context.
+    add_paths(_masks.back());
 
-    gnash::bitmap_info*        create_bitmap_info_rgb(image::rgb* 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.
-       {
-           return new bitmap_info_cairo(im);
-       }
+    // Save the context so we can return to the former clip later.
+    cairo_save(_cr);
 
+    // Clip the fills defined by the current paths.
+    cairo_clip(_cr);
+    
+    // Remove the current path since we have no further use for it (and may
+    // confuse us later). 
+    cairo_new_path(_cr);
 
-    gnash::bitmap_info*        create_bitmap_info_rgba(image::rgba* im)
-       // Given an image, returns a pointer to a bitmap_info class
-       // that can later be passed to fill_style_bitmap(), to set a
-       // bitmap fill style.
-       //
-       // This version takes an image with an alpha channel.
-       {
-           return new bitmap_info_cairo(im);
        }
 
-    gnash::bitmap_info*        create_bitmap_info_alpha(int w, int h, uint8_t* 
data)
-       // Create a bitmap_info so that it contains an alpha texture
-       // with the given data (1 byte per texel).
+  virtual void disable_mask()
        {
-           return new bitmap_info_cairo(w, h, data);
-       }
+    // Restore the previous clip.
+    cairo_restore(_cr);
 
+    _masks.pop_back();
+  }
 
-    void       delete_bitmap_info(gnash::bitmap_info* bi)
-       // Delete the given bitmap info class.
+  void add_path(cairo_t* cr, const path& cur_path)
        {
-           delete bi;
+    cairo_move_to(cr, cur_path.m_ax, cur_path.m_ay);
+    
+    float prev_x = cur_path.m_ax,
+          prev_y = cur_path.m_ay;
+    
+    for (std::vector<edge>::const_iterator it = cur_path.m_edges.begin(),
+         end = cur_path.m_edges.end(); it != end; ++it) {
+      const edge& cur_edge = *it;
+      
+      if (cur_edge.is_straight()) {
+        cairo_line_to(cr, cur_edge.m_ax, cur_edge.m_ay);
+      } else {
+      
+        // Cairo expects a cubic Bezier curve, while Flash gives us a
+        // quadratic one. We must apply a conversion:
+        
+        const float two_thirds = 2.0/3.0;
+        const float one_third = 1 - two_thirds;
+        
+        float x1 = prev_x + two_thirds * (cur_edge.m_cx - prev_x);
+        float y1 = prev_y + two_thirds * (cur_edge.m_cy - prev_y);
+        
+        float x2 = cur_edge.m_cx + one_third * (cur_edge.m_ax - cur_edge.m_cx);
+        float y2 = cur_edge.m_cy + one_third * (cur_edge.m_ay - cur_edge.m_cy);
+        
+        const float& x3 = cur_edge.m_ax;
+        const float& y3 = cur_edge.m_ay;
+    
+    
+        cairo_curve_to(cr, x1, y1, x2, y2, x3, y3);
        }
 
+      prev_x = cur_edge.m_ax;
+      prev_y = cur_edge.m_ay;
 
-    // Constructor
-    render_handler_cairo() :
-       m_cr_mask(0), m_view_width(0), m_view_height(0),
-       m_video_buffer(0), m_video_bufsize(0)
-    {
-       cairo_surface_t* dummy = cairo_image_surface_create(
-           CAIRO_FORMAT_A8, 1, 1);
-       m_cr_dummy = cairo_create(dummy);
-       cairo_surface_destroy(dummy);
     }
 
-    // Destructor
-    ~render_handler_cairo()
-    {
-       if (m_video_buffer)  delete [] m_video_buffer;
-       if (m_cr_mask)  cairo_destroy(m_cr_mask);
-       cairo_destroy(m_cr_dummy);
     }
 
-    void       begin_display(
-       const gnash::rgba& background_color,
-       int /*viewport_x0*/, int /*viewport_y0*/,
-       int viewport_width, int viewport_height,
-       float x0, float x1, float y0, float y1)
-       // 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.
-       {
-           g_cr = (g_cr_output ? g_cr_output : m_cr_dummy);
-
-           m_display_width  = fabsf(x1 - x0);
-           m_display_height = fabsf(y1 - y0);
-           m_view_width  = viewport_width;
-           m_view_height = viewport_height;
-
-           cairo_identity_matrix(g_cr);
-           cairo_rectangle(g_cr, x0, y0, m_display_width, m_display_height);
-           cairo_clip(g_cr);
-           cairo_scale(g_cr, viewport_width / m_display_width,
-               viewport_height / m_display_height);
-           cairo_translate(g_cr, x0, y0);
 
-           // Clear the background, if background color has alpha > 0.
-           if (background_color.m_a > 0)
+  PathPtrVec
+  get_paths_by_style(const PathVec& path_vec, unsigned int style)
                {
-                   // Draw a big quad.
-                   apply_color(background_color);
-                   cairo_rectangle(g_cr, x0, y0, x1 - x0, y1 - y0);
-                   cairo_fill(g_cr);
+    PathPtrVec paths;
+    for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
+         it != end; ++it) {
+      const path& cur_path = *it;
+      
+      if (cur_path.m_fill0 == style) {
+        paths.push_back(&cur_path);
                }
+      
+      if (cur_path.m_fill1 == style) {
+        paths.push_back(&cur_path);
        }
 
+    }
+    return paths;
+  }
 
-    void       end_display()
-       // Clean up after rendering a frame.
+  void apply_line_style(const line_style& style, const cxform& cx)
        {
+    float width = style.get_width();
+
+    if ( width == 0.0 ) {
+      // TODO: test this!
+      cairo_set_line_width(_cr, 1.0); // expected: 1 pixel
+    } else {
+      cairo_set_line_width(_cr, width);
        }
 
+    rgba color = cx.transform(style.get_color());
 
-    void       set_matrix(const gnash::matrix& m)
-       // Set the current transform for mesh & line-strip rendering.
+    set_color(color);
+  }
+  
+  std::vector<cairo_pattern_t*>
+  build_cairo_styles(const std::vector<fill_style>& fill_styles, const cxform& 
cx,
+                     const matrix& mat)
        {
-           m_current_matrix = m;
+    std::vector<cairo_pattern_t*> styles_vec_cairo;
+
+    for (std::vector<fill_style>::const_iterator it = fill_styles.begin(),
+         end = fill_styles.end(); it != end; ++it) {
+      const fill_style& cur_style = *it;
+      
+      cairo_pattern_t* pattern = get_cairo_pattern(cur_style, cx, mat);
+      styles_vec_cairo.push_back(pattern);
        }
 
+    return styles_vec_cairo;
+  }
 
-    void       set_cxform(const gnash::cxform& cx)
-       // Set the current color transform for mesh & line-strip rendering.
+  void
+  pattern_add_color_stops(const fill_style& style, cairo_pattern_t* pattern,
+                          const cxform& cx)
        {
-           m_current_cxform = cx;
+    for (int index = 0; index < style.get_color_stop_count(); ++index) {
+    
+      const gradient_record& grad = style.get_color_stop(index);
+      
+      rgba c = cx.transform(grad.m_color);
+
+      cairo_pattern_add_color_stop_rgba (pattern,
+        grad.m_ratio / 255.0, c.m_r / 255.0, c.m_g / 255.0,
+        c.m_b / 255.0, c.m_a / 255.0);
+    }
        }
        
-    static void        apply_matrix(const gnash::matrix& m)
-       // add user space transformation
+  cairo_pattern_t*
+  get_cairo_pattern(const fill_style& style, const cxform& cx, const matrix& 
mat)
+  {
+    int fill_type = style.get_type();
+    cairo_pattern_t* pattern = NULL;
+        
+    switch (fill_type) {
+
+      case SWF::FILL_LINEAR_GRADIENT:
        {
+        matrix m = style.get_gradient_matrix();
+        matrix cm;
+        cm.set_inverse(mat);
+        m.concatenate(cm);         
+      
            cairo_matrix_t mat;
-           cairo_matrix_init(&mat, m.m_[0][0], m.m_[1][0], m.m_[0][1],
-               m.m_[1][1], m.m_[0][2], m.m_[1][2]);
-           cairo_transform(g_cr, &mat);
-       }
+        init_cairo_matrix(&mat, m);
+        
+        pattern = cairo_pattern_create_linear(0, 0, 256.0, 0);
+        cairo_pattern_set_matrix (pattern, &mat);
+        
+        pattern_add_color_stops(style, pattern, cx);
 
-    static void        apply_color(const gnash::rgba& c)
-       // Set the given color.
+        break;
+      }
+      case SWF::FILL_RADIAL_GRADIENT:
        {
-           cairo_set_source_rgba(g_cr,
-               c.m_r / 255.0, c.m_g / 255.0, c.m_b / 255.0, c.m_a / 255.0);
+        matrix m = style.get_gradient_matrix();
+        matrix cm;
+        cm.set_inverse(mat);
+        m.concatenate(cm);
+        
+        // move the center of the radial fill to where it should be, according 
to Udo
+        gnash::matrix transl;
+        transl.concatenate_translation(-32.0f, -32.0f);
+        transl.concatenate(m);  
+      
+        cairo_matrix_t mat;
+        init_cairo_matrix(&mat, transl);
+        
+        pattern = cairo_pattern_create_radial(0.0, 0.0, 0.0, 0.0, 0.0, 32.0);
+
+        cairo_pattern_set_matrix (pattern, &mat);          
+        
+        pattern_add_color_stops(style, pattern, cx);
+        break;
        }
+      case SWF::FILL_FOCAL_GRADIENT:
+      {
+        log_unimpl("focal gradient fill");
 
-    void       fill_style_disable(int fill_side)
-       // Don't fill on the {0 == left, 1 == right} side of a path.
+        break;
+      }              
+      case SWF::FILL_TILED_BITMAP_HARD:
+      case SWF::FILL_TILED_BITMAP:
+      case SWF::FILL_CLIPPED_BITMAP:
+      case SWF::FILL_CLIPPED_BITMAP_HARD:
        {
-           assert(fill_side >= 0 && fill_side < 2);
+        matrix m = style.get_bitmap_matrix();        
 
-           m_current_styles[fill_side].disable();
+        bitmap_info_cairo* binfo
+          = static_cast<bitmap_info_cairo*>(style.get_bitmap_info());
+
+        if (!binfo) {
+          return NULL;
        }
 
+        cairo_matrix_t mat;
+        init_cairo_matrix(&mat, m);       
+
+        pattern = binfo->apply(&mat, fill_type);
+        
+        break;
+      } 
 
-    void       line_style_disable()
-       // Don't draw a line on this path.
+      case SWF::FILL_SOLID:
        {
-           m_current_styles[LINE_STYLE].disable();
+        rgba c = cx.transform(style.get_color());
+        pattern = cairo_pattern_create_rgba (c.m_r / 255.0, c.m_g / 255.0,
+                                             c.m_b / 255.0, c.m_a / 255.0);
+        break;
        }
 
+    } // switch
 
-    void       fill_style_color(int fill_side, const gnash::rgba& color)
-       // Set fill style for the left interior of the shape.  If
-       // enable is false, turn off fill for the left interior.
-       {
-           assert(fill_side >= 0 && fill_side < 2);
+    return pattern;
 
-           
m_current_styles[fill_side].set_color(m_current_cxform.transform(color));
        }
 
-
-    void       line_style_color(const gnash::rgba& color)
-       // Set the line style of the shape.  If enable is false, turn
-       // off lines for following curve segments.
+  void draw_outlines(const PathVec& path_vec, const std::vector<line_style>& 
line_styles, const cxform& cx)
        {
-           
m_current_styles[LINE_STYLE].set_color(m_current_cxform.transform(color));
+    cairo_set_line_cap(_cr, CAIRO_LINE_CAP_ROUND); // TODO: move to init
+
+    for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
+         it != end; ++it) {
+      const path& cur_path = *it;
+      if (!cur_path.m_line) {
+        continue;
        }
 
+      apply_line_style(line_styles[cur_path.m_line-1], cx);
 
-    void       fill_style_bitmap(int fill_side, const gnash::bitmap_info* bi, 
const gnash::matrix& m, bitmap_wrap_mode wm)
-       {
-           assert(fill_side >= 0 && fill_side < 2);
-           m_current_styles[fill_side].set_bitmap(bi, m, wm, m_current_cxform);
+      add_path(_cr, cur_path);
+      
+      cairo_stroke(_cr);
+    }  
        }
        
-    void       line_style_width(float width)
-       {
-           if ( width == 1.0 ) // "hairline"
+  void apply_matrix(cairo_t* cr, const gnash::matrix& m)
+       // add user space transformation
            {
-               width = 20;
-           }
-           cairo_set_line_width(g_cr, width); // twips expected, it seems
+           cairo_matrix_t mat;
+           init_cairo_matrix(&mat, m);
+           cairo_transform(cr, &mat);
        }
 
 
-    void       draw_mesh_strip(const void* coords, int vertex_count)
+       
+       void
+       draw_subshape(PathVec& path_vec,
+         const matrix& mat,
+    const cxform& cx,
+    float pixel_scale,
+    const std::vector<cairo_pattern_t*>& fill_styles,
+    const std::vector<line_style>& line_styles)
        {
-           // Set up current style.
-           m_current_styles[LEFT_STYLE].apply();
+    for (size_t i = 0; i < fill_styles.size(); ++i) {
+      PathPtrVec paths = get_paths_by_style(path_vec, i+1);
 
-           cairo_save(g_cr);
-           apply_matrix(m_current_matrix);
 
-           // Draw the tris in cairo
-           const int16_t* vertex = static_cast<const int16_t*>(coords);
-           for (;  vertex_count > 2;  vertex_count--, vertex += 2)
-           {
-               cairo_move_to(g_cr, vertex[0], vertex[1]);
-               cairo_line_to(g_cr, vertex[2], vertex[3]);
-               cairo_line_to(g_cr, vertex[4], vertex[5]);
+      for (PathPtrVec::const_iterator iter = paths.begin(), final = 
paths.end();
+           iter != final; ++iter) {
+        const path* cur_path = *iter;
+        
+        add_path(_cr, *cur_path);
+        
+      } // for (PathVec..)
+
+      if (paths.size()) {
+        cairo_set_source(_cr, fill_styles[i]);
+        cairo_fill(_cr);
            }
 
-           cairo_surface_t* mask = 0;
-           if (m_cr_mask)  mask = cairo_get_target(m_cr_mask);
+    } // for(std::vector<fill_style> ..)
 
-           if (mask)  cairo_mask_surface(g_cr, mask, 0, 0);
-           else  cairo_fill(g_cr);
 
-           if (m_current_styles[LEFT_STYLE].needs_second_pass())
-               {
-                   m_current_styles[LEFT_STYLE].apply_second_pass();
-                   for (;  vertex_count > 2;  vertex_count--, vertex += 2)
+    
+    draw_outlines(path_vec, line_styles, cx);
+    
+  }
+       
+        
+  std::vector<PathVec::const_iterator>
+       find_subshapes(const PathVec& path_vec)
                    {
-                       cairo_move_to(g_cr, vertex[0], vertex[1]);
-                       cairo_line_to(g_cr, vertex[2], vertex[3]);
-                       cairo_line_to(g_cr, vertex[4], vertex[5]);
+    std::vector<PathVec::const_iterator> subshapes;
+    
+    PathVec::const_iterator it = path_vec.begin(),
+                            end = path_vec.end();
+    
+    subshapes.push_back(it);
+    ++it;
+
+    for (;it != end; ++it) {
+      const path& cur_path = *it;
+         
+           if (cur_path.m_new_shape) {
+             subshapes.push_back(it); 
                    }
-                   if (mask)  cairo_mask_surface(g_cr, mask, 0, 0);
-                   else  cairo_fill(g_cr);
-                   m_current_styles[LEFT_STYLE].cleanup_second_pass();
                }
 
-           cairo_restore(g_cr);
-       }
+         subshapes.push_back(end);
 
+         return subshapes;
+       }
 
-    void       draw_line_strip(const void* coords, int vertex_count)
-       // Draw the line strip formed by the sequence of points.
+  void draw_mask(const PathVec& path_vec)
        {
-           // Set up current style.
-           m_current_styles[LINE_STYLE].apply();
+    for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
+         it != end; ++it) {
+      const path& cur_path = *it;
 
-           cairo_save(g_cr);
-           apply_matrix(m_current_matrix);
+      if (cur_path.m_fill0 || cur_path.m_fill1) {
+        _masks.back().push_back(cur_path);     
+      }
+    }  
+  }
 
-           // Draw the line-strip in cairo
-           const int16_t* vertex = static_cast<const int16_t*>(coords);
-           cairo_move_to(g_cr, vertex[0], vertex[1]);
-           for (vertex += 2;  vertex_count > 1;  vertex_count--, vertex += 2)
-               cairo_line_to(g_cr, vertex[0], vertex[1]);
-           cairo_stroke(g_cr);
+  void
+  add_paths(const PathVec& path_vec)
+  {
+    for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
+         it != end; ++it) {
+      const path& cur_path = *it;
 
-           cairo_restore(g_cr);
+      add_path(_cr, cur_path);
+    }  
        }
 
+  /// Takes a path and translates it using the given matrix. The new path
+  /// is stored in paths_out.
+  /// Taken from render_handler_agg.cpp.  
+  void apply_matrix_to_paths(const std::vector<path> &paths_in, 
+    std::vector<path> &paths_out, const matrix& mat) {
 
-    void       draw_bitmap(
-       const gnash::matrix& m,
-       const gnash::bitmap_info* binfo,
-       const gnash::rect& coords,
-       const gnash::rect& /*uv_coords*/,
-       const gnash::rgba& color)
-       // Draw a rectangle textured with the given bitmap, with the
-       // given color.  Apply given transform; ignore any currently
-       // set transforms.
-       //
-       // Intended for textured glyph rendering.
-       {
-            gnash::bitmap_info* nonconst_binfo = 
const_cast<gnash::bitmap_info*>(binfo);
-           bitmap_info_cairo* bi = 
dynamic_cast<bitmap_info_cairo*>(nonconst_binfo);
-           assert(bi);
+    int pcount, ecount;
+    int pno, eno;
 
-           apply_color(color);
+    // copy path
+    paths_out = paths_in;    
+    pcount = paths_out.size();        
 
-           gnash::point a, b, c, d;
-           m.transform(&a, gnash::point(coords.get_x_min(), 
coords.get_y_min()));
-           m.transform(&b, gnash::point(coords.get_x_max(), 
coords.get_y_min()));
-           m.transform(&c, gnash::point(coords.get_x_max(), 
coords.get_y_max()));
-           m.transform(&d, gnash::point(coords.get_x_min(), 
coords.get_y_max()));
+    for (pno=0; pno<pcount; pno++) {
 
-           // FIXME!!! scaling and offset is wrong
-           cairo_matrix_t mat;
-           cairo_matrix_init_scale(&mat, coords.width(), coords.height());
-           cairo_matrix_init_translate(&mat, coords.get_x_min(), 
coords.get_y_min());
+      path &the_path = paths_out[pno];     
+      point oldpnt(the_path.m_ax, the_path.m_ay);
+      point newpnt;
+      mat.transform(&newpnt, oldpnt);
+      the_path.m_ax = newpnt.m_x;    
+      the_path.m_ay = newpnt.m_y;
 
-           cairo_matrix_t new_mat;
-           cairo_matrix_init(&new_mat, m.m_[0][0], m.m_[1][0], m.m_[0][1],
-               m.m_[1][1], m.m_[0][2], m.m_[1][2]);
+      ecount = the_path.m_edges.size();
+      for (eno=0; eno<ecount; eno++) {
 
-           cairo_matrix_multiply(&mat, &mat, &new_mat);
+        edge &the_edge = the_path.m_edges[eno];
 
-           cairo_pattern_t* pattern = bi->m_pattern;
-           cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
-           cairo_pattern_set_matrix(pattern, &mat);
-           cairo_set_source(g_cr, pattern);
+        oldpnt.m_x = the_edge.m_ax;
+        oldpnt.m_y = the_edge.m_ay;
+        mat.transform(&newpnt, oldpnt);
+        the_edge.m_ax = newpnt.m_x;
+        the_edge.m_ay = newpnt.m_y;
 
-           cairo_save(g_cr);
-           cairo_move_to(g_cr, a.m_x, a.m_y);
-           cairo_line_to(g_cr, b.m_x, b.m_y);
-           cairo_line_to(g_cr, c.m_x, c.m_y);
-           cairo_line_to(g_cr, d.m_x, d.m_y);
-           cairo_clip(g_cr);
-           cairo_paint(g_cr);
-           cairo_restore(g_cr);
-       }
+        oldpnt.m_x = the_edge.m_cx;
+        oldpnt.m_y = the_edge.m_cy;
+        mat.transform(&newpnt, oldpnt);
+        the_edge.m_cx = newpnt.m_x;
+        the_edge.m_cy = newpnt.m_y;
        
-    void begin_submit_mask()
-       {
-           if (m_cr_mask)  cairo_destroy(m_cr_mask);
-           cairo_surface_t* mask = cairo_image_surface_create(
-               CAIRO_FORMAT_A8, m_view_width, m_view_height);
-           m_cr_mask = cairo_create(mask);
-           cairo_surface_destroy(mask);
+      }          
 
-           // Start drawing to the mask
-           g_cr = m_cr_mask;
        }
        
-    void end_submit_mask()
-       {            
-           // Finished with the mask.  Now draw to output
-           g_cr = (g_cr_output ? g_cr_output : m_cr_dummy);
        }
        
-    void disable_mask()
-       {              
-           // Clean up any mask
-           if (m_cr_mask)
+
+  virtual void draw_shape_character(shape_character_def *def, 
+    const matrix& mat,
+    const cxform& cx,
+    float pixel_scale,
+    const std::vector<fill_style>& fill_styles,
+    const std::vector<line_style>& line_styles)
            {
-               cairo_destroy(m_cr_mask);
-               m_cr_mask = 0;
 
-               // Prepare to draw to output
-               g_cr = (g_cr_output ? g_cr_output : m_cr_dummy);
-           }
+    const PathVec& path_vec = def->get_paths();
+    
+    if (!path_vec.size()) {
+      return;    
        }
        
-       // Returns the format the current renderer wants videoframes in.
-       int videoFrameFormat() {
-               return RGB;
+    cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_EVEN_ODD); // TODO: Move to init
+        
+    if (_drawing_mask) {      
+      PathVec scaled_path_vec;
+      
+      apply_matrix_to_paths(path_vec, scaled_path_vec, mat);
+      draw_mask(scaled_path_vec); 
+      return;
        }
        
-       /// Draws the video frames
-       void drawVideoFrame(image::image_base* baseframe, const matrix* m, 
const rect* bounds){
-           // Obtain on-stage bounding rectangle
-           gnash::point a, b, c, d;
-           m->transform(&a, gnash::point(bounds->get_x_min(), 
bounds->get_y_min()));
-           m->transform(&b, gnash::point(bounds->get_x_max(), 
bounds->get_y_min()));
-           m->transform(&c, gnash::point(bounds->get_x_max(), 
bounds->get_y_max()));
-           m->transform(&d, gnash::point(bounds->get_x_min(), 
bounds->get_y_max()));
+    cairo_matrix_t old_matrix;
+    cairo_get_matrix(_cr, &old_matrix);
 
-           // Extract frame attributes
-           image::rgb* frame = static_cast<image::rgb*>(baseframe);
-           int         w = frame->width();
-           int         h = frame->height();
+    apply_matrix(_cr, mat); 
 
-           // Compute bounding rectangle size relative to video object
-           double w_scale = bounds->width()  / w;
-           double h_scale = bounds->height() / h;
 
-           // Fit video to bounding rectangle
-           cairo_matrix_t mat;
-           cairo_matrix_init_scale(&mat, w_scale, h_scale);
-           cairo_matrix_translate(&mat,
-               bounds->get_x_min(), bounds->get_y_min());
+    std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
 
-           // Now apply transformation to video
-           cairo_matrix_t frame_mat;
-           cairo_matrix_init(&frame_mat,
-               m->m_[0][0], m->m_[1][0],
-               m->m_[0][1], m->m_[1][1],
-               m->m_[0][2], m->m_[1][2]);
-           cairo_matrix_multiply(&mat, &mat, &frame_mat);
+    std::vector<cairo_pattern_t*> fill_styles_cairo
+      = build_cairo_styles(fill_styles, cx, mat);
 
-           // Inverse the matrix for pattern space
-           cairo_matrix_invert(&mat);
+    for (size_t i = 0; i < subshapes.size()-1; ++i) {
+      PathVec subshape_paths;
 
-           // Convert RGB frame to cairo format
-           int buf_size = w * h * 4;
-           if (m_video_bufsize < buf_size)
-           {
-               if (m_video_buffer)  delete [] m_video_buffer;
-               m_video_buffer  = new unsigned char[buf_size];
-               m_video_bufsize = buf_size;
+      if (subshapes[i] != subshapes[i+1]) {
+        subshape_paths = PathVec(subshapes[i], subshapes[i+1]);
+      } else {
+        subshape_paths.push_back(*subshapes[i]);
            }
-           rgb_to_cairo_rgb24(m_video_buffer, frame);
 
-           // Create a pattern from the the RGB frame
-           cairo_surface_t* surface = cairo_image_surface_create_for_data(
-               m_video_buffer, CAIRO_FORMAT_RGB24, w, h, w * 4);
-           cairo_pattern_t* pattern = 
cairo_pattern_create_for_surface(surface);
-           cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
-           cairo_pattern_set_matrix(pattern, &mat);
+      draw_subshape(subshape_paths, mat, cx, pixel_scale, fill_styles_cairo,
+                    line_styles);
+    }
 
-           // Draw the frame now
-           cairo_save(g_cr);
-           cairo_set_source(g_cr, pattern);
-           cairo_move_to(g_cr, a.m_x, a.m_y);
-           cairo_line_to(g_cr, b.m_x, b.m_y);
-           cairo_line_to(g_cr, c.m_x, c.m_y);
-           cairo_line_to(g_cr, d.m_x, d.m_y);
-           cairo_clip(g_cr);
-           cairo_paint(g_cr);
-           cairo_restore(g_cr);
+    destroy_cairo_patterns(fill_styles_cairo);
 
-           // Clean up
+    cairo_set_matrix(_cr, &old_matrix);
+  }
+  
+  void
+  destroy_cairo_patterns(std::vector<cairo_pattern_t*>& patterns)
+  {
+    for (std::vector<cairo_pattern_t*>::iterator it = patterns.begin(),
+         end = patterns.end(); it != end; ++it) {
+      cairo_pattern_t* pattern = *it;
+      if (pattern && cairo_pattern_get_type(pattern) !=
+                     CAIRO_PATTERN_TYPE_SURFACE) {
            cairo_pattern_destroy(pattern);
-           cairo_surface_destroy(surface);
+      }
+    }
        }
 
-};     // end class render_handler_cairo
+  virtual void draw_glyph(shape_character_def *def, const matrix& mat,
+    const rgba& color, float pixel_scale)
+  {
 
+    cxform dummy_cx;
+    std::vector<fill_style> glyph_fs;
 
-// bitmap_info_cairo implementation
+    fill_style coloring;
+    coloring.setSolid(color);
 
-bitmap_info_cairo::bitmap_info_cairo()
-// Make a placeholder bitmap_info.  Must be filled in later before using.
-{
-    m_buffer = 0;
-    m_image = 0;
-    m_original_width = 0;
-    m_original_height = 0;
-}
+    glyph_fs.push_back(coloring);
 
+    const PathVec& path_vec = def->get_paths();
 
-bitmap_info_cairo::bitmap_info_cairo(int width, int height, uint8_t* data)
-// Initialize this bitmap_info to an alpha image
-// containing the specified data (1 byte per texel).
-{
-    assert(width > 0);
-    assert(height > 0);
-    assert(data);
-
-    // Allocate output buffer
-    int buf_size = width * height;
-    m_buffer = new unsigned char[buf_size];
-
-    // Copy alpha data
-    memcpy(m_buffer, data, buf_size);
-
-    // Create the image
-    m_original_width  = width;
-    m_original_height = height;
-    m_image = cairo_image_surface_create_for_data(
-       m_buffer, CAIRO_FORMAT_A8, width, height, width);
-    m_pattern = cairo_pattern_create_for_surface(m_image);
-}
+    std::vector<line_style> dummy_ls;
+    draw_shape_character(def, mat, dummy_cx, pixel_scale, glyph_fs, dummy_ls); 
+  }
 
+  virtual bool allow_glyph_textures()
+  {
+    return false;
+  }
 
-bitmap_info_cairo::bitmap_info_cairo(image::rgb* im)
-// Version of the constructor that takes an RGB image.
-{
-    assert(im);
+  void
+  set_context(cairo_t* context)
+  {
+    if (context == _cr) {
+      return;    
+    }
+    if (cairo_get_reference_count(_cr)) {
+      cairo_destroy(_cr);
+    }
+    _cr = context;
+  }
 
-    // Convert 24-bit BGR data to 32-bit RGB
-    int buf_size = im->width() * im->height() * 4;
-    m_buffer = new unsigned char[buf_size];
-    rgb_to_cairo_rgb24(m_buffer, im);
+  void
+  init_cairo_matrix(cairo_matrix_t* cairo_matrix, const matrix& gnash_matrix)
+  {
+    cairo_matrix_init(cairo_matrix,
+           gnash_matrix.m_[0][0], gnash_matrix.m_[1][0],
+           gnash_matrix.m_[0][1], gnash_matrix.m_[1][1],
+           gnash_matrix.m_[0][2], gnash_matrix.m_[1][2]);
+  }
 
-    // Create the cairo image
-    m_original_width  = im->width();
-    m_original_height = im->height();
-    m_image = cairo_image_surface_create_for_data(m_buffer,
-       CAIRO_FORMAT_RGB24, im->width(), im->height(), im->width() * 4);
-    m_pattern = cairo_pattern_create_for_surface(m_image);
-}
+private:
+  /// The cairo context.
+  cairo_t* _cr;
+  boost::scoped_array<uint8_t> _video_buffer;
+  std::vector<PathVec> _masks;
+  size_t _video_bufsize;
+  bool _drawing_mask;
 
+}; // class render_handler_cairo
 
-bitmap_info_cairo::bitmap_info_cairo(image::rgba* im)
-// Version of the constructor that takes an image with alpha.
-{
-    assert(im);
 
-    // Allocate output buffer
-    size_t buf_size = im->size(); 
 
-    // TODO: who owns this buffer ??
-    m_buffer = new unsigned char[buf_size];
-    rgba_to_cairo_argb32(m_buffer, im);
-
-    // Create the image
-    m_original_width  = im->width();
-    m_original_height = im->height();
-    m_image = cairo_image_surface_create_for_data(m_buffer,
-       CAIRO_FORMAT_ARGB32, im->width(), im->height(), im->width() * 4);
-    m_pattern = cairo_pattern_create_for_surface(m_image);
-}
+
+
+namespace renderer {
+
+
+namespace cairo
+{
 
 DSOEXPORT render_handler*
 create_handler()
@@ -761,20 +892,15 @@
 }
 
 DSOEXPORT void
-set_handle(cairo_t* handle)
+set_context(render_handler* handler, cairo_t* context)
 {
-    g_cr_output = handle;
+  render_handler_cairo* cairo_handler = 
static_cast<render_handler_cairo*>(handler);
+  cairo_handler->set_context(context);
 }
 
 
-
-} // namespace gnash::renderer::cairo
-} // namespace gnash::renderer
+} // namespace cairo
+} // namespace renderer
 } // namespace gnash
 
 
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:
-/* vim: set cindent tabstop=8 softtabstop=4 shiftwidth=4: */

Index: backend/render_handler_cairo.h
===================================================================
RCS file: /sources/gnash/gnash/backend/render_handler_cairo.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- backend/render_handler_cairo.h      1 Jul 2007 10:53:48 -0000       1.6
+++ backend/render_handler_cairo.h      18 Oct 2007 09:05:40 -0000      1.7
@@ -18,12 +18,14 @@
 // 
 //
 
-/* $Id: render_handler_cairo.h,v 1.6 2007/07/01 10:53:48 bjacques Exp $ */
+/* $Id: render_handler_cairo.h,v 1.7 2007/10/18 09:05:40 bjacques Exp $ */
 
 #ifndef BACKEND_RENDER_HANDLER_CAIRO_H
 #define BACKEND_RENDER_HANDLER_CAIRO_H
 
 #include "tu_config.h"
+#include <cairo/cairo.h>
+#include "render_handler.h"
 
 namespace gnash {
 namespace renderer {
@@ -35,7 +37,7 @@
 gnash::render_handler* create_handler();
 
 /// Make sure to call this before starting display
-void set_handle(cairo_t* handle);
+void set_context(render_handler* handler, cairo_t* context);
 
 } // namespace gnash::renderer::cairo
 } // namespace gnash::renderer

Index: gui/gtk_glue_cairo.cpp
===================================================================
RCS file: /sources/gnash/gnash/gui/gtk_glue_cairo.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- gui/gtk_glue_cairo.cpp      1 Jul 2007 10:54:02 -0000       1.11
+++ gui/gtk_glue_cairo.cpp      18 Oct 2007 09:05:40 -0000      1.12
@@ -59,7 +59,9 @@
 render_handler*
 GtkCairoGlue::createRenderHandler()
 {
-    return renderer::cairo::create_handler();
+    _renderer = renderer::cairo::create_handler();
+
+    return _renderer;
 }
 
 void
@@ -80,18 +82,25 @@
     if (!_drawing_area)  return;
 
     // Create cairo handle for output window
-    if (_cairo_handle)  cairo_destroy(_cairo_handle);
+    if (_cairo_handle) {
+      assert(cairo_get_reference_count(_cairo_handle));
+      cairo_destroy(_cairo_handle);
+    }
     _cairo_handle = gdk_cairo_create(_drawing_area->window);
     assert(_cairo_handle);
 
     // Create offscreen image for rendering
-    if (_cairo_offscreen)  cairo_destroy(_cairo_offscreen);
+    if (_cairo_offscreen) {
+      assert(cairo_get_reference_count(_cairo_offscreen));
+      cairo_destroy(_cairo_offscreen);
+    }
+    
     cairo_surface_t* surface = cairo_image_surface_create(
        CAIRO_FORMAT_RGB24, event->width, event->height);
     _cairo_offscreen = cairo_create(surface);
-    assert(_cairo_offscreen);
     cairo_surface_destroy(surface);
-    renderer::cairo::set_handle(_cairo_offscreen);
+
+    renderer::cairo::set_context(_renderer, _cairo_offscreen);
 }
 
 

Index: gui/gtk_glue_cairo.h
===================================================================
RCS file: /sources/gnash/gnash/gui/gtk_glue_cairo.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- gui/gtk_glue_cairo.h        9 Jul 2007 07:26:44 -0000       1.12
+++ gui/gtk_glue_cairo.h        18 Oct 2007 09:05:40 -0000      1.13
@@ -45,6 +45,7 @@
   private:
     cairo_t     *_cairo_handle;
     cairo_t     *_cairo_offscreen;
+    render_handler* _renderer;
 };
 
 } // namespace gnash




reply via email to

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