Re: Problems with transparent background

Martin Fischer <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
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);

-- 
cairo mailing list
[email protected]
https://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.