/*******************************************************************************/ /* Copyright (C) 2012 Jonathan Moore Liles */ /* */ /* This program is free software; you can redistribute it and/or modify it */ /* under the terms of the GNU Library General Public License as published */ /* by the Free Software Foundation; either version 2 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; see the file COPYING. If not,write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ /* This class emulates the FLTK graphics drawing API using the Cairo * library. The advantage of doing this is that it provides * antialiasing and transparency on X11 for all FLTK widgets. * * The implementation inherits from the Xlib driver and attempts to * keep colors, clipping, and matrix transformations in sync, so that * calls to the base Xlib and Cairo routines can be mixed with the * expected results. * * Fonts are still rendered using XFT. And since the FLTK image * drawing implementation already uses XRender, there would seem to be * little advantage to using Cairo for that either. * * Alpha values can be encoded into Fl_Color values by using the new * fl_color_add_alpha function--with the caveat that 100% transparency * (an Alpha of 0) is unsupported. This allows existing boxes and * widgets to be drawn with transparency simply by setting their * color() to one with an alpha value encoded. * * Antialiasing can be turned on and off with the new * fl_set_antialias() function. However, it should be noted that, even * with antialiasing disabled drawing complex lines and polygons is * still significantly slower with Cairo than with the base FLTK * routines. * */ #include #include double fl_hxo = 0.0; double fl_hyo = 0.5; double fl_vxo = 0.5; double fl_vyo = 0.0; double fl_vho = 1.0; double fl_hwo = 1.0; #define HXO(n) ( n + fl_hxo ) #define HYO(n) ( n + fl_hyo ) #define VXO(n) ( n + fl_vxo ) #define VYO(n) ( n + fl_vyo ) #define VHO(n) ( n + fl_vho ) #define HWO(n) ( n + fl_hwo ) Fl_Color fl_color_add_alpha ( Fl_Color c, uchar alpha ) { if ( !( c & 0xFFFFFF00 ) ) { /* this is an indexed color or black */ if ( c & 0x000000FF ) { /* this is an indexed color */ uchar r,g,b; Fl::get_color( c, r, g, b ); c = fl_rgb_color( r, g, b ); } else { /* this is black */ if ( 0 == alpha ) { /* sorry, you can't have zero opacity because we don't * have enough bits and it doesn't make much sense anyway */ alpha = 255; } /* hack to represent black */ c = 0x01010100; } } return ( c & 0xFFFFFF00 ) | alpha; } #include #include #include #include #include #include static double lw = 1; static double hlw; static cairo_antialias_t aa = CAIRO_ANTIALIAS_GRAY; static int npoints = 0; cairo_matrix_t Fl_Cairo_Graphics_Driver::m; cairo_matrix_t Fl_Cairo_Graphics_Driver::stack[FL_MATRIX_STACK_SIZE]; int Fl_Cairo_Graphics_Driver::sptr; #define cairo_set_antialias( cr, aa ) Fl_Cairo_Graphics_Driver::Fl_Cairo_Graphics_Driver ( ) : Fl_Xlib_Graphics_Driver () { // rstackptr = 0; } /* void Fl_Cairo_Graphics_Driver::set_current ( void ) */ /* { */ /* Window root; */ /* int x, y; */ /* unsigned int w, h, bw, d; */ /* XGetGeometry( fl_display, fl_window, &root, &x, &y, &w, &h, &bw, &d ); */ /* fl_cairo_surface = cairo_create_surface( fl_gc, w, h ); */ /* /\* FIXME: how are we going to free this? *\/ */ /* fl_cairo_context = cairo_create( fl_cairo_surface ); */ /* cairo_surface_destroy( fl_cairo_surface ); */ /* fl_cairo_surface = 0; */ /* } */ #define set_cairo_matrix() \ { \ cairo_t *cr = fl_cairo_context; \ if ( sptr ) \ cairo_set_matrix( cr, &m ); \ else \ cairo_identity_matrix( cr ); \ } #define restore_cairo_matrix() \ { \ cairo_t *cr = fl_cairo_context; \ cairo_identity_matrix( cr ); \ } void Fl_Cairo_Graphics_Driver::push_matrix ( void ) { cairo_t *cr = Fl::cairo_cc(); cairo_get_matrix( cr, &m ); if (sptr==FL_MATRIX_STACK_SIZE) Fl::error("fl_push_matrix(): matrix stack overflow."); else stack[sptr++] = m; } void Fl_Cairo_Graphics_Driver::pop_matrix ( void ) { cairo_t *cr = Fl::cairo_cc(); if (sptr==0) Fl::error("fl_pop_matrix(): matrix stack underflow."); else m = stack[--sptr]; set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::translate ( double x, double y ) { cairo_t *cr = Fl::cairo_cc(); cairo_matrix_translate( &m, x, y ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::scale ( double x, double y ) { cairo_t *cr = Fl::cairo_cc(); cairo_matrix_scale( &m, x, y ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::rotate ( double a ) { cairo_t *cr = Fl::cairo_cc(); cairo_matrix_rotate( &m, a * ( M_PI / 180.0 ) ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::mult_matrix ( double a, double b, double c, double d, double x, double y ) { cairo_t *cr = Fl::cairo_cc(); cairo_matrix_t m2; cairo_matrix_init( &m2, a, b, c, d, x, y ); cairo_matrix_multiply( &m, &m2, &m ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::line_style ( int style, int t, char* ) { cairo_t *cr = Fl::cairo_cc(); if ( t == 0 || t == 1 ) { double w1, w2; w1 = w2 = 1.0; cairo_device_to_user_distance (cr, &w1, &w2); lw = w1 > w2 ? w1 : w2; } else lw = t; hlw = lw / 2.0; cairo_set_line_width( cr, lw ); cairo_set_line_cap( cr, CAIRO_LINE_CAP_BUTT ); if ( style & FL_DASH ) { const double dash[] = { lw, lw }; int len = sizeof(dash) / sizeof(dash[0]); cairo_set_dash( cr, dash, len, 0 ); } else if ( style & FL_DOT ) { const double dash[] = { lw, lw }; int len = sizeof(dash) / sizeof(dash[0]); cairo_set_dash( cr, dash, len, 0 ); cairo_set_line_cap( cr, CAIRO_LINE_CAP_ROUND ); } else { cairo_set_dash( cr, NULL, 0, 0 ); } } void Fl_Cairo_Graphics_Driver::color ( Fl_Color c ) { uchar r,g,b; Fl_Xlib_Graphics_Driver::color( c ); if ( ( c & 0x000000ff ) && ! ( c & 0xFFFFFF00 ) ) { /* color is indexed, get the RGB value */ Fl::get_color( c, r, g, b ); /* FIXME: temp! */ color( r, g, b ); /* color( 255, 0, 0, 50 ); */ } else { Fl::get_color( c & 0xFFFFFF00, r, g, b ); /* lower 8 bits become alpha. */ uchar a = c & 0x000000ff; if ( ! a ) a = 255; /* /\* HACK to represent black *\/ */ /* if ( ( c & 0xFFFFFF00 ) == 0x01010100 ) */ /* r = g = b = 0; */ color( r, g, b, a ); } } void Fl_Cairo_Graphics_Driver::color ( uchar r, uchar g, uchar b ) { cairo_t *cr = Fl::cairo_cc(); Fl_Xlib_Graphics_Driver::color( r, g, b ); if ( ! cr ) return; cairo_set_source_rgb( cr, r / 255.0f, g / 255.0f, b / 255.0f ); } void fl_set_antialias ( int v ) { cairo_t *cr = Fl::cairo_cc(); switch ( v ) { case FL_ANTIALIAS_DEFAULT: cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_DEFAULT ); break; case FL_ANTIALIAS_ON: cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_GRAY ); break; case FL_ANTIALIAS_OFF: cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_NONE ); break; } } void Fl_Cairo_Graphics_Driver::color ( Fl_Color c, uchar a ) { uchar r,g,b; Fl::get_color( c, r, g, b ); Fl_Xlib_Graphics_Driver::color( c ); color( r, g, b, a); } void Fl_Cairo_Graphics_Driver::color (uchar r, uchar g, uchar b, uchar a ) { cairo_t *cr = Fl::cairo_cc(); // Fl_Xlib_Graphics_Driver::color( r, g, b ); if ( ! cr ) return; cairo_set_source_rgba( cr, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ); } void Fl_Cairo_Graphics_Driver::circle( double x, double y, double r ) { cairo_t *cr = Fl::cairo_cc(); cairo_arc( cr, x, y, r, 0, 2.0f * M_PI ); restore_cairo_matrix(); if ( what == POLYGON ) cairo_fill( cr ); else cairo_stroke( cr ); set_cairo_matrix(); } /* static void add_arc( int x, int y, int w, int h, double a1, double a2 ) */ /* { */ /* cairo_t *cr = Fl::cairo_cc(); */ /* /\* const double line_width = cairo_get_line_width( cr ); *\/ */ /* const double cx = x + ( 0.5f * w ); */ /* const double cy = y + ( 0.5f * h ); */ /* /\* cairo_save( cr ); *\/ */ /* /\* cairo_translate( cr, cx, cy ); *\/ */ /* /\* cairo_scale( cr, w, h ); *\/ */ /* /\* if ( a1 > a2 ) *\/ */ /* /\* cairo_arc( cr, 0.0, 0.0, 0.5, a1 * ( -M_PI / 180.0 ), a2 * ( -M_PI / 180.0 )); *\/ */ /* /\* else *\/ */ /* /\* cairo_arc_negative( cr, 0.0, 0.0, 0.5, a1 * ( -M_PI / 180.0 ), a2 * ( -M_PI / 180.0 )); *\/ */ /* cairo_save( cr ); */ /* cairo_translate( cr, cx, cy ); */ /* cairo_scale( cr, w - 1, h - 1 ); */ /* if ( a1 > a2 ) */ /* cairo_arc( cr, 0.0, 0.0, 0.5, a1 * ( -M_PI / 180.0 ), a2 * ( -M_PI / 180.0 )); */ /* else */ /* cairo_arc_negative( cr, 0.0, 0.0, 0.5, a1 * ( -M_PI / 180.0 ), a2 * ( -M_PI / 180.0 )); */ /* cairo_restore( cr ); */ /* } */ static void add_arc( int x, int y, int w, int h, double a1, double a2, bool pie ) { cairo_t *cr = Fl::cairo_cc(); double a1R = a1 * ( M_PI / 180.0 ); double a2R = a2 * ( M_PI / 180.0 ); double cx = x + 0.5 * w, cy = y + 0.5 * h; cairo_save( cr ); cairo_translate( cr, cx, cy ); // cairo_scale( cr, (w - lw), 0 - ((h - lw) )); cairo_scale( cr, w, 0 - h ); if ( a1 > a2 ) cairo_arc_negative( cr, 0.0, 0.0, 0.5, a1R, a2R ); else cairo_arc( cr, 0.0, 0.0, 0.5, a1R, a2R ); if ( pie ) { cairo_line_to( cr, 0, 0 ); cairo_close_path( cr ); } cairo_restore( cr ); } void Fl_Cairo_Graphics_Driver::arc( int x, int y, int w, int h, double a1, double a2 ) { cairo_t *cr = Fl::cairo_cc(); add_arc( x, y, w, h, a1, a2, false ); restore_cairo_matrix(); cairo_stroke( cr ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::arc( double x, double y, double r, double a1, double a2 ) { cairo_t *cr = Fl::cairo_cc(); cairo_close_path( cr ); cairo_arc( cr, x, y, r, a1 * ( -M_PI / 180.0 ), a2 * ( -M_PI / 180.0 )); } void Fl_Cairo_Graphics_Driver::pie( int x, int y, int w, int h, double a1, double a2 ) { cairo_t *cr = Fl::cairo_cc(); add_arc( x, y, w, h, a1, a2, true ); restore_cairo_matrix(); cairo_fill( cr ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::line( int x1, int y1, int x2, int y2 ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); // restore_cairo_matrix(); if ( x1 == x2 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); /* vertical line */ if ( y1 > y2 ) { int t = y2; y2 = y1; y1 = t; } cairo_move_to( cr, VXO( x1 ), VYO( y1 ) ); cairo_line_to( cr, VXO( x2 ), VHO( y2 ) ); } else if ( y1 == y2 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); /* horizontal line */ cairo_move_to( cr, HXO( x1 ), HYO( y1 ) ); cairo_line_to( cr, HWO( x2 ), HYO( y2 ) ); } else { /* diagonal line */ cairo_move_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); } cairo_stroke( cr ); // set_cairo_matrix(); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::line( int x1, int y1, int x2, int y2, int x3, int y3 ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } // restore_cairo_matrix(); cairo_move_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); cairo_line_to( cr, x3 , y3 ); cairo_stroke( cr ); // set_cairo_matrix(); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::rect ( int x, int y, int w, int h ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); /* cairo draws lines half inside and half outside of the path... */ /* const double line_width = cairo_get_line_width( cr ); */ /* const double o = line_width / 2.0; */ cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); // restore_cairo_matrix(); // cairo_rectangle( cr, x + hlw, y + hlw, w - lw - 1, h - lw - 1); cairo_rectangle( cr, VXO( x ), HYO( y ), w - 1, h - 1 ); cairo_stroke( cr ); // set_cairo_matrix(); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::rectf ( int x, int y, int w, int h ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); // restore_cairo_matrix(); /* cairo fills the inside of the path... */ cairo_rectangle( cr, x, y, w, h ); cairo_fill( cr ); // set_cairo_matrix(); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::begin_line ( void ) { what = LINE; npoints = 0; } void Fl_Cairo_Graphics_Driver::begin_points ( void ) { what = POINT_; npoints = 0; } void Fl_Cairo_Graphics_Driver::begin_polygon ( void ) { what = POLYGON; npoints = 0; } void Fl_Cairo_Graphics_Driver::begin_loop ( void ) { what = LOOP; npoints = 0; } void Fl_Cairo_Graphics_Driver::begin_complex_polygon ( void ) { what = POLYGON; npoints = 0; } void Fl_Cairo_Graphics_Driver::end_line ( void ) { cairo_t *cr = Fl::cairo_cc(); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_set_line_width( cr, lw ); restore_cairo_matrix(); cairo_stroke( cr ); set_cairo_matrix(); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::end_points ( void ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); cairo_fill( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::end_loop ( void ) { if ( npoints < 3 ) { end_line(); return; } cairo_t *cr = Fl::cairo_cc(); cairo_close_path( cr ); end_line(); } /* static double last_vertex_x; */ /* static double last_vertex_y; */ void Fl_Cairo_Graphics_Driver::vertex ( double x, double y ) { cairo_t *cr = Fl::cairo_cc(); if ( !npoints ) cairo_move_to( cr, x, y ); else cairo_line_to( cr, x, y ); ++npoints; } void Fl_Cairo_Graphics_Driver::gap ( void ) { npoints = 0; } void Fl_Cairo_Graphics_Driver::end_complex_polygon ( void ) { if ( npoints < 3 ) { end_line(); return; } cairo_t *cr = Fl::cairo_cc(); cairo_close_path( cr ); restore_cairo_matrix(); cairo_fill( cr ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::end_polygon ( void ) { if ( npoints < 3 ) { end_line(); return; } cairo_t *cr = Fl::cairo_cc(); cairo_close_path( cr ); restore_cairo_matrix(); cairo_fill( cr ); set_cairo_matrix(); } void Fl_Cairo_Graphics_Driver::curve( double x, double y, double x1, double y1, double x2, double y2, double x3, double y3 ) { cairo_t *cr = Fl::cairo_cc(); cairo_move_to( cr, x, y ); cairo_curve_to( cr, x1, y1, x2, y2, x3, y3 ); } void Fl_Cairo_Graphics_Driver::polygon ( int x, int y, int x1, int y1, int x2, int y2 ) { cairo_t *cr = Fl::cairo_cc(); cairo_move_to( cr, x , y ); cairo_line_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); cairo_close_path( cr ); cairo_fill( cr ); } void Fl_Cairo_Graphics_Driver::polygon ( int x, int y, int x1, int y1, int x2, int y2, int x3, int y3 ) { cairo_t *cr = Fl::cairo_cc(); cairo_move_to( cr, x , y ); cairo_line_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); cairo_line_to( cr, x3 , y3 ); cairo_close_path( cr ); cairo_fill( cr ); } void Fl_Cairo_Graphics_Driver::loop ( int x, int y, int x1, int y1, int x2, int y2 ) { cairo_t *cr = Fl::cairo_cc(); cairo_move_to( cr, x , y ); cairo_line_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); cairo_close_path( cr ); cairo_stroke( cr ); } void Fl_Cairo_Graphics_Driver::loop ( int x, int y, int x1, int y1, int x2, int y2, int x3, int y3 ) { cairo_t *cr = Fl::cairo_cc(); cairo_move_to( cr, x , y ); cairo_line_to( cr, x1 , y1 ); cairo_line_to( cr, x2 , y2 ); cairo_line_to( cr, x3 , y3 ); cairo_close_path( cr ); cairo_stroke( cr ); } void Fl_Cairo_Graphics_Driver::xyline ( int x, int y, int x1 ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_move_to( cr, HXO( x ), HYO( y ) ); cairo_line_to( cr, HWO( x1 ), HYO( y ) ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::xyline ( int x, int y, int x1, int y2 ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } /* horizontal line */ cairo_move_to( cr, HXO( x ) , HYO( y ) ); cairo_line_to( cr, HWO( x1 ), HYO( y ) ); /* then vertical line */ cairo_line_to( cr, HWO( x1 ) , VYO( y2 ) ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::xyline ( int x, int y, int x1, int y2, int x3 ) { cairo_t *cr = Fl::cairo_cc(); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_move_to( cr, x , y ); cairo_line_to( cr, x1 , y ); cairo_line_to( cr, x1 , y2 ); cairo_line_to( cr, x3 , y2 ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::yxline ( int x, int y, int y1 ) { cairo_t *cr = Fl::cairo_cc(); cairo_set_line_width( cr, lw ); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_move_to( cr, VXO( x ), VHO( y ) ); cairo_line_to( cr, VXO( x ), VYO( y1 ) ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::yxline ( int x, int y, int y1, int x2 ) { cairo_t *cr = Fl::cairo_cc(); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_move_to( cr, x , y ); cairo_line_to( cr, x, y1 ); cairo_line_to( cr, x2, y1 ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::yxline ( int x, int y, int y1, int x2, int y3 ) { cairo_t *cr = Fl::cairo_cc(); if ( lw <= 1 ) { cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); } cairo_move_to( cr, x , y ); cairo_line_to( cr, x , y1 ); cairo_line_to( cr, x2 , y1 ); cairo_line_to( cr, x2 , y3 ); cairo_stroke( cr ); cairo_set_antialias( cr, aa ); } static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, int &X, int &Y, int &W, int &H) { fl_clip_box(XP,YP,WP,HP,X,Y,W,H); cx += X-XP; cy += Y-YP; // clip the box down to the size of image, quit if empty: if (cx < 0) {W += cx; X -= cx; cx = 0;} if (cx+W > w) W = w-cx; if (W <= 0) return 1; if (cy < 0) {H += cy; Y -= cy; cy = 0;} if (cy+H > h) H = h-cy; if (H <= 0) return 1; return 0; } void Fl_Cairo_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { int X, Y, W, H; // Don't draw an empty image... if (!img->d() || !img->array) { // img->draw_empty(XP, YP); return; } if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { return; } /* if (!img->id_) { */ /* img->id_ = fl_create_offscreen(img->w(), img->h()); */ /* if ((img->d() == 2 || img->d() == 4) ) { */ /* fl_begin_offscreen((Fl_Offscreen)img->id_); */ /* fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); */ /* fl_end_offscreen(); */ /* } */ /* } */ cairo_t *cr = Fl::cairo_cc(); cairo_format_t fmt; switch (img->d() ) { case 4: fmt = CAIRO_FORMAT_ARGB32; break; case 3: fmt = CAIRO_FORMAT_RGB24; break; case 1: fmt = CAIRO_FORMAT_A8; break; } /* cairo_save( cr ); */ /* cairo_reset_clip( cr ); */ cairo_surface_t *image = cairo_image_surface_create_for_data( (unsigned char *)img->array, fmt, img->w(), img->h( ), cairo_format_stride_for_width( fmt, img->w() ) ); /* cairo_surface_t *image = cairo_image_surface_create_for_data( (unsigned char *)img->array, fmt, img->w(), img->h(), img->ld() ); */ /* cairo_patter_t *pat = cairo_surface_pattern( image ); */ /* cairo_matrix_t matr; */ /* cairo_matrix_scale( &matr, */ cairo_set_source_surface( cr, image, X - cx, Y - cy ); cairo_rectangle( cr, X, Y, W, H ); cairo_fill(cr); cairo_surface_destroy( image ); /* cairo_restore( cr ); */ }