From a95122a573b69eb16632c49adbc34bbf13f9cc85 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Tue, 20 Mar 2012 19:25:58 -0700 Subject: [PATCH] Cleanup Cairo support and improve drawing alignment. --- FL/Enumerations.H | 2 + FL/Fl.H | 16 +- FL/Fl_Cairo.H | 42 +---- FL/Fl_Cairo_Window.H | 2 - FL/Fl_Device.H | 39 +++-- FL/fl_draw.H | 2 +- src/Fl_Cairo.cxx | 11 +- src/Fl_Cairo_Graphics_Driver.cxx | 349 +++++++++++++++++++++++++++++---------- src/Fl_Device.cxx | 36 +++- src/Fl_arg.cxx | 12 ++ src/Fl_x.cxx | 29 +++- test/cairo_test.cxx | 3 - 12 files changed, 364 insertions(+), 179 deletions(-) diff --git a/FL/Enumerations.H b/FL/Enumerations.H index 093422b..80ec2fe 100644 --- a/FL/Enumerations.H +++ b/FL/Enumerations.H @@ -822,6 +822,8 @@ FL_EXPORT Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg); FL_EXPORT Fl_Color fl_color_average(Fl_Color c1, Fl_Color c2, float weight); +FL_EXPORT Fl_Color fl_color_add_alpha( Fl_Color c, uchar alpha ); + /** Returns a lighter version of the specified color. */ inline Fl_Color fl_lighter(Fl_Color c) { return fl_color_average(c, FL_WHITE, .67f); } diff --git a/FL/Fl.H b/FL/Fl.H index ee6eddd..4f6e718 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -1057,27 +1057,15 @@ public: You can use Fl::cairo_cc() to get the current cairo context anytime. \note Only available when configure has the --enable-cairo option */ - static void cairo_autolink_context(bool alink) {cairo_state_.autolink(alink);} - /** - Gets the current autolink mode for cairo support. - \retval false if no cairo context autolink is made for each window. - \retval true if any fltk window is attached a cairo context when it - is current. \see void cairo_autolink_context(bool alink) - \note Only available when configure has the --enable-cairo option - */ - static bool cairo_autolink_context() {return cairo_state_.autolink();} /** Gets the current cairo context linked with a fltk window. */ - static cairo_t * cairo_cc() { return cairo_state_.cc(); } + static cairo_t * cairo_cc() { return fl_cairo_context; } /** Sets the current cairo context to \p c. Set \p own to true if you want fltk to handle this cc deletion. \note Only available when configure has the --enable-cairo option */ - static void cairo_cc(cairo_t * c, bool own=false){ cairo_state_.cc(c, own); } +// static void cairo_cc(cairo_t * c, bool own=false){ cairo_state_.cc(c, own); } private: - /* static cairo_t * cairo_make_current(void* gc); */ - /* static cairo_t * cairo_make_current(void* gc, int W, int H); */ - static Fl_Cairo_State cairo_state_; public: /** @} */ diff --git a/FL/Fl_Cairo.H b/FL/Fl_Cairo.H index aaa9a76..21f52fc 100644 --- a/FL/Fl_Cairo.H +++ b/FL/Fl_Cairo.H @@ -48,46 +48,10 @@ # error Cairo is not supported on that platform. # endif -/** - \addtogroup group_cairo - @{ -*/ - -/** - Contains all the necessary info on the current cairo context. - A private internal & unique corresponding object is created to - permit cairo context state handling while keeping it opaque. - For internal use only. - \note Only available when configure has the --enable-cairo option -*/ -class FL_EXPORT Fl_Cairo_State { -public: - Fl_Cairo_State() : cc_(0), own_cc_(false), autolink_(true), window_(0), gc_(0) {} - - // access attributes - cairo_t* cc() const {return cc_;} ///< Gets the current cairo context - bool autolink() const {return autolink_;} ///< Gets the autolink option. See Fl::cairo_autolink_context(bool) - /** Sets the current cairo context, \p own indicates cc deletion is handle externally by user */ - void cc(cairo_t* c, bool own=true) { - if (cc_ && own_cc_) cairo_destroy(cc_); - cc_=c; - if (!cc_) window_=0; - own_cc_=own; - } - void autolink(bool b); ///< Sets the autolink option, only available with --enable-cairoext - void window(void* w) {window_=w;} ///< Sets the window \p w to keep track on - void* window() const {return window_;} ///< Gets the last window attached to a cc - void gc(void* c) {gc_=c;} ///< Sets the gc \p c to keep track on - void* gc() const {return gc_;} ///< Gets the last gc attached to a cc - -private: - cairo_t * cc_; // contains the unique autoupdated cairo context - bool own_cc_; // indicates whether we must delete the cc, useful for internal cleanup - bool autolink_; // true by default, permits to prevent the automatic cairo mapping on fltk windows for custom cairo implementations - void* window_, *gc_; // for keeping track internally of last win+gc treated -}; +FL_EXPORT extern cairo_surface_t *fl_cairo_surface; +FL_EXPORT extern cairo_t *fl_cairo_context; -/** @} */ +cairo_surface_t * cairo_create_surface(void * gc, int W, int H); # endif // FLTK_HAVE_CAIRO diff --git a/FL/Fl_Cairo_Window.H b/FL/Fl_Cairo_Window.H index e8bc75c..291885e 100644 --- a/FL/Fl_Cairo_Window.H +++ b/FL/Fl_Cairo_Window.H @@ -64,8 +64,6 @@ protected: void draw() { Fl_Double_Window::draw(); // manual method ? if yes explicitly get a cairo_context here - if (!Fl::cairo_autolink_context()) - Fl::cairo_make_current(this); if (draw_cb_) draw_cb_(this, Fl::cairo_cc()); } diff --git a/FL/Fl_Device.H b/FL/Fl_Device.H index 7f68f5c..2ba6e2f 100644 --- a/FL/Fl_Device.H +++ b/FL/Fl_Device.H @@ -116,28 +116,34 @@ public: struct matrix {double a, b, c, d, x, y;}; private: static const matrix m0; - Fl_Font font_; // current font - Fl_Fontsize size_; // current font size - Fl_Color color_; // current color - int sptr; + static Fl_Font font_; // current font + static Fl_Fontsize size_; // current font size + static Fl_Color color_; // current color + static int sptr; static const int matrix_stack_size = FL_MATRIX_STACK_SIZE; - matrix stack[FL_MATRIX_STACK_SIZE]; - matrix m; + static matrix stack[FL_MATRIX_STACK_SIZE]; + static matrix m; protected: enum {LINE, LOOP, POLYGON, POINT_}; - int n, p_size, gap_; - XPOINT *p; - int what; + static int n; + static int p_size; + static int gap_; + static XPOINT *p; + static int what; private: - int fl_clip_state_number; - int rstackptr; + static int fl_clip_state_number; + static int rstackptr; static const int region_stack_max = FL_REGION_STACK_SIZE - 1; - Fl_Region rstack[FL_REGION_STACK_SIZE]; + static Fl_Region rstack[FL_REGION_STACK_SIZE]; #ifdef WIN32 int numcount; int counts[20]; #endif Fl_Font_Descriptor *font_descriptor_; + +public: + + static matrix *fl_matrix; /**< Points to the current coordinate transformation matrix */ protected: void transformed_vertex0(COORD_T x, COORD_T y); @@ -221,8 +227,6 @@ protected: friend FL_EXPORT void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D); friend FL_EXPORT void gl_start(); - matrix *fl_matrix; /**< Points to the current coordinate transformation matrix */ - /** \brief The constructor. */ Fl_Graphics_Driver(); /** \brief see fl_rect(int x, int y, int w, int h). */ @@ -498,12 +502,13 @@ public: }; #if FLTK_USE_CAIRO -FL_EXPORT Fl_Color fl_color_add_alpha ( Fl_Color c, uchar alpha ); class Fl_Cairo_Graphics_Driver : public Fl_Xlib_Graphics_Driver { public: +// void set_current(void); + Fl_Cairo_Graphics_Driver ( ); /* static const char *class_id; */ @@ -574,6 +579,7 @@ public: class FL_EXPORT Fl_Surface_Device : public Fl_Device { /** \brief The graphics driver in use by this surface. */ Fl_Graphics_Driver *_driver; +public: static Fl_Surface_Device *_surface; // the surface that currently receives graphics output protected: /** \brief Constructor that sets the graphics driver to use for the created surface. */ @@ -596,7 +602,8 @@ public: \brief A display to which the computer can draw. */ class FL_EXPORT Fl_Display_Device : public Fl_Surface_Device { - static Fl_Display_Device *_display; // the platform display device +public: +static Fl_Display_Device *_display; // the platform display device public: static const char *class_id; const char *class_name() {return class_id;}; diff --git a/FL/fl_draw.H b/FL/fl_draw.H index 0220458..41f9155 100644 --- a/FL/fl_draw.H +++ b/FL/fl_draw.H @@ -200,7 +200,7 @@ enum { FL_JOIN_BEVEL = 0x3000 ///< join style: line join is tidied }; -#if FLTK_USE_CAIRO +#if FLTK_HAVE_CAIRO FL_EXPORT Fl_Color fl_color_add_alpha ( Fl_Color c, uchar alpha ); #endif diff --git a/src/Fl_Cairo.cxx b/src/Fl_Cairo.cxx index e24dc55..5f943da 100644 --- a/src/Fl_Cairo.cxx +++ b/src/Fl_Cairo.cxx @@ -35,14 +35,11 @@ #include #endif -// static Fl module initialization : -Fl_Cairo_State Fl::cairo_state_; ///< contains all necesary info for current cairo context mapping - /* Creates transparently a cairo_surface_t object. gc is an HDC context in WIN32, a CGContext* in Quartz, a display on X11 */ -static cairo_surface_t * cairo_create_surface(void * gc, int W, int H) { +cairo_surface_t * cairo_create_surface(void * gc, int W, int H) { # if defined(USE_X11) return cairo_xlib_surface_create(fl_display, fl_window, fl_visual->visual, W, H); # elif defined(WIN32) @@ -54,6 +51,8 @@ static cairo_surface_t * cairo_create_surface(void * gc, int W, int H) { # endif } +cairo_surface_t *fl_cairo_surface; +cairo_t *fl_cairo_context; cairo_t * Fl::cairo_make_current(Fl_Window* wi) { @@ -67,9 +66,9 @@ Fl::cairo_make_current(Fl_Window* wi) { // cairo_surface_destroy( s ); } - cairo_state_.window(wi); + fl_cairo_surface = wi->i->cs; + fl_cairo_context = wi->i->cc; - Fl::cairo_cc( wi->i->cc ); return wi->i->cc; } diff --git a/src/Fl_Cairo_Graphics_Driver.cxx b/src/Fl_Cairo_Graphics_Driver.cxx index d6c152a..5d4cc1c 100644 --- a/src/Fl_Cairo_Graphics_Driver.cxx +++ b/src/Fl_Cairo_Graphics_Driver.cxx @@ -46,10 +46,55 @@ */ #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; +} #if FLTK_USE_CAIRO -#include #include #include #include @@ -59,13 +104,34 @@ static double lw = 1; static double hlw; +static cairo_antialias_t aa = CAIRO_ANTIALIAS_GRAY; +#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; */ +/* } */ + void Fl_Cairo_Graphics_Driver::restore_clip ( void ) { cairo_t *cr = Fl::cairo_cc(); @@ -75,10 +141,10 @@ void Fl_Cairo_Graphics_Driver::restore_clip ( void ) Fl_Xlib_Graphics_Driver::restore_clip(); - Fl_Region r = clip_region(); - cairo_reset_clip( cr ); + Fl_Region r = clip_region(); + if ( r ) { XRectangle rect; @@ -130,19 +196,25 @@ void Fl_Cairo_Graphics_Driver::color ( Fl_Color c ) { /* 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 { - /* lower 8 bits become alpha. */ - // if (i & 0xffffff00) { - Fl::get_color( c, r, g, b ); + 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 ); } } @@ -166,45 +238,17 @@ void fl_set_antialias ( int v ) switch ( v ) { case FL_ANTIALIAS_DEFAULT: - cairo_set_antialias( cr, CAIRO_ANTIALIAS_DEFAULT ); + cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_DEFAULT ); break; case FL_ANTIALIAS_ON: - cairo_set_antialias( cr, CAIRO_ANTIALIAS_GRAY ); + cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_GRAY ); break; case FL_ANTIALIAS_OFF: - cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); + cairo_set_antialias( cr, aa = CAIRO_ANTIALIAS_NONE ); break; } } -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; - } - } - } - - return ( c & 0xFFFFFF00 ) & alpha; -} void Fl_Cairo_Graphics_Driver::color ( Fl_Color c, uchar a ) { @@ -221,7 +265,7 @@ 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 ); +// Fl_Xlib_Graphics_Driver::color( r, g, b ); if ( ! cr ) return; @@ -265,14 +309,25 @@ static void add_arc( int x, int y, int w, int h, double a1, double a2 ) 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, h ); + 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 ); } @@ -290,6 +345,8 @@ void Fl_Cairo_Graphics_Driver::arc( double x, double y, double r, double a1, dou { 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 )); } @@ -300,7 +357,7 @@ void Fl_Cairo_Graphics_Driver::pie( int x, int y, int w, int h, double a1, doubl double a1R = a1 * ( M_PI / 180.0 ); double a2R = a2 * ( M_PI / 180.0 ); - float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; + float cx = x + 0.5 * w - 0.5f, cy = y + 0.5 * h - 0.5f; cairo_save( cr ); cairo_translate( cr, cx, cy ); @@ -317,19 +374,60 @@ void Fl_Cairo_Graphics_Driver::line( int x1, int y1, int x2, int y2 ) { cairo_t *cr = Fl::cairo_cc(); - cairo_move_to( cr, x1 + 0.5, y1 + 0.5 ); - cairo_line_to( cr, x2 + 0.5, y2 + 0.5 ); + cairo_set_line_width( cr, lw ); + + + 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 ); + + 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_move_to( cr, x1 + 0.5, y1 + 0.5 ); - cairo_line_to( cr, x2 + 0.5, y2 + 0.5); - cairo_line_to( cr, x3 + 0.5, y3 + 0.5 ); + cairo_set_line_width( cr, lw ); + + if ( lw <= 1 ) + { + cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); + } + + cairo_move_to( cr, x1 , y1 ); + cairo_line_to( cr, x2 , y2 ); + cairo_line_to( cr, x3 , y3 ); cairo_stroke( cr ); + + cairo_set_antialias( cr, aa ); } @@ -337,23 +435,33 @@ 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 ); + // cairo_rectangle( cr, x + hlw, y + hlw, w - lw - 1, h - lw - 1); - cairo_rectangle( cr, x + 0.5, y + 0.5, w, h ); + cairo_rectangle( cr, VXO( x ), HYO( y ), w - 1, h - 1 ); cairo_stroke( cr ); + + 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 ); + /* cairo fills the inside of the path... */ - cairo_rectangle( cr, x + 0.5, y + 0.5, w, h ); + cairo_rectangle( cr, x, y, w, h ); cairo_fill( cr ); + + cairo_set_antialias( cr, aa ); } void Fl_Cairo_Graphics_Driver::end_line ( void ) @@ -366,22 +474,35 @@ void Fl_Cairo_Graphics_Driver::end_line ( void ) return; } - cairo_move_to( cr, p[0].x + 0.5, p[0].y + 0.5 ); + if ( lw <= 1 ) + { + cairo_set_antialias( cr, CAIRO_ANTIALIAS_NONE ); + } + + cairo_set_line_width( cr, lw ); + + cairo_move_to( cr, p[0].x + 0.5 , p[0].y + 0.5 ); for (int i=1; i 0 ) v = use_cairo_stack[--use_cairo_ptr]; - + if ( v ) + { + /* FIXME: why are there *SO MANY VERSIONS OF THE SAME THING*? */ fl_graphics_driver = &fl_cairo_driver; + Fl_Surface_Device::_surface = (Fl_Surface_Device*)&fl_cairo_display; + Fl_Display_Device::_display = &fl_cairo_display; + } else + { fl_graphics_driver = &fl_xlib_driver; + Fl_Surface_Device::_surface = (Fl_Surface_Device*)&fl_xlib_display; + Fl_Display_Device::_display = &fl_xlib_display; + } + + fl_restore_clip(); + #else /* noop */ ; diff --git a/test/cairo_test.cxx b/test/cairo_test.cxx index 8981186..417a19a 100644 --- a/test/cairo_test.cxx +++ b/test/cairo_test.cxx @@ -144,9 +144,6 @@ static void my_cairo_draw_cb(Fl_Cairo_Window* window, cairo_t* cr) { } int main(int argc, char** argv) { -#ifdef AUTOLINK - Fl::cairo_autolink_context(true); -#endif Fl_Cairo_Window window(300,300); window.resizable(&window); -- 2.11.4.GIT