[cairo] Problems with transparent background

Martin Fischer martinfischer8 at t-online.de
Fri Feb 24 16:00:48 UTC 2017


Hi there,

none of the suggestions really solved the problem I'm having with 
overlaying surfaces.

With some experimenting I was able to create a simpler testcase:

- - - -
/*
  * gcc raster2.c -o raster2 `pkg-config --cflags --libs gtk+-2.0`
  */

#include <gtk/gtk.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>

struct {
   cairo_surface_t *image;
   cairo_surface_t *ball;
} glob;

double px = 97;
double py = 97;

/* create a grid of green lines on solid white as background */

void CreateBackground()
{
     cairo_t *cr;
     int i;
	
     glob.image = cairo_recording_surface_create(		 
CAIRO_CONTENT_COLOR_ALPHA, NULL);

     cr = cairo_create( glob.image );

     cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
     cairo_paint(cr);

     cairo_set_source_rgba(cr,0,1.0,0, 1.0);

     for( i = 0; i <= 200; i+=10 ) {
		cairo_move_to( cr, i, 0 );
		cairo_line_to( cr, i, 200 );
		cairo_move_to( cr, 0, i );
		cairo_line_to(cr, 200, i );
     }
     cairo_stroke(cr);
     cairo_destroy(cr);
}

/* create a red dot */

void CreateForeground()
{
     cairo_t *cr;

     glob.ball = cairo_recording_surface_create 
(CAIRO_CONTENT_COLOR_ALPHA, NULL);

     cr = cairo_create( glob.ball );

     // draw a red dot
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
     cairo_arc(cr, px, py, 12, 0, 2*M_PI);
     cairo_fill(cr);

     cairo_destroy(cr);
}

/* when called, invalidate the position of the red dot and force
  * a redraw
  */

gboolean timeout(gpointer data)
{
     GtkWidget *widget = GTK_WIDGET(data);
     GdkRectangle rect;

     rect.x = px - 6;
     rect.y = py - 6;
     rect.width = 12;
     rect.height = 12;		
     gdk_window_invalidate_rect( widget->window, &rect, FALSE );
     gtk_widget_queue_draw(widget);

     return TRUE;
}

/* draw the animation:
  * 1. clip to the changed area
  * 2. draw the background
  * 3. draw the surface containing the red dot on top
  */

gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
     cairo_t *cr = gdk_cairo_create(widget->window);

     cairo_rectangle(cr, event->area.x, event->area.y, 
event->area.width, event->area.height);
     cairo_clip(cr);

     /* draw the background */
     cairo_set_source_surface( cr, glob.image, 0, 0 );
     cairo_paint(cr);

     /* draw the foreground */
     cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
     cairo_set_source_surface( cr, glob.ball, 0, 0 );
     cairo_paint(cr);
	
     cairo_destroy( cr );

     return FALSE;
}

int main(int argc, char *argv[])
{
     char *title = "Test";
     cairo_t *cr;

     gtk_init(NULL,NULL);
		
     GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(window),title);
     gtk_container_set_border_width(GTK_CONTAINER (window), 2);

     g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit),&window);

     GtkWidget *drawing_area = gtk_drawing_area_new();
     gtk_widget_set_size_request(drawing_area, 200, 200);
     g_signal_connect(drawing_area, "expose_event", 
G_CALLBACK(expose),NULL);
     gtk_container_add(GTK_CONTAINER(window), drawing_area);

     CreateBackground();
     CreateForeground();

     g_timeout_add(10, timeout, window);

     if (!GTK_WIDGET_VISIBLE (window))
         gtk_widget_show_all(window);
     else {
         gtk_widget_hide (window);
         window = NULL;
     }

     gtk_main();

     cairo_surface_destroy(glob.image);
     cairo_surface_destroy(glob.ball);
}

- - - -

This code produces a grid of green lines on solid white as a background. 
Then I overlay a surface that only has a red dot in its center. After 
that regular redraws are enforced by invalidating the area every 10 ms. 
On my system I get a flickering background that has artifacts from other 
areas of my screen. Looks like an invalid /uninitialized pointer.

When I change both surfaces to image surfaces by calling 
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 200, 200 ) instead of 
the cairo_recording_surface_create() calls shown above, everything works 
as expected. So this situation seems to be related to recording surfaces.

Question for me is: do I misunderstand something or is this a bug in 
recording surfaces?

Regards
Martin

On 22.02.2017 22:03 Lawrence D'Oliveiro wrote:
> On Wed, 22 Feb 2017 19:30:13 +0100, Martin Fischer wrote:
>
>> gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer
>> data) {
>>       cairo_t *cr = gdk_cairo_create(widget->window);
>>
>>       if( glob.image == NULL )
>> 		CreateBackground( cairo_get_target (cr));
>> 		
>>       cairo_rectangle(cr, event->area.x, event->area.y,
>> event->area.width, event->area.height);
>>       cairo_clip(cr);
>>       cairo_set_source_surface(cr, glob.image, 0, 0);
>
> Maybe add
>
>   	cairo_set_operator( cr, CAIRO_OPERATOR_SOURCE );
>
> at some point before the following paint call?
>
>>       cairo_paint(cr);



More information about the cairo mailing list