2 * Copyright (C) 2005 Red Hat, Inc.
3 * Based on cairo-demo/X11/cairo-knockout.c
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
28 oval_path (cairo_t
*cr
,
34 cairo_translate (cr
, xc
, yc
);
35 cairo_scale (cr
, 1.0, yr
/ xr
);
36 cairo_move_to (cr
, xr
, 0.0);
41 cairo_close_path (cr
);
46 /* Create a path that is a circular oval with radii xr, yr at xc,
49 /* Fill the given area with checks in the standard style
50 * for showing compositing effects.
52 * It would make sense to do this as a repeating surface,
53 * but most implementations of RENDER currently have broken
54 * implementations of repeat + transform, even when the
55 * transform is a translation.
58 fill_checks (cairo_t
*cr
,
60 int width
, int height
)
66 cairo_rectangle (cr
, x
, y
, width
, height
);
67 cairo_set_source_rgb (cr
, 0.4, 0.4, 0.4);
70 /* Only works for CHECK_SIZE a power of 2 */
71 j
= x
& (-CHECK_SIZE
);
73 for (; j
< height
; j
+= CHECK_SIZE
)
75 i
= y
& (-CHECK_SIZE
);
76 for (; i
< width
; i
+= CHECK_SIZE
)
77 if ((i
/ CHECK_SIZE
+ j
/ CHECK_SIZE
) % 2 == 0)
78 cairo_rectangle (cr
, i
, j
, CHECK_SIZE
, CHECK_SIZE
);
81 cairo_set_source_rgb (cr
, 0.7, 0.7, 0.7);
85 /* Draw a red, green, and blue circle equally spaced inside
86 * the larger circle of radius r at (xc, yc)
89 draw_3circles (cairo_t
*cr
,
94 double subradius
= radius
* (2 / 3. - 0.1);
96 cairo_set_source_rgba (cr
, 1., 0., 0., alpha
);
98 xc
+ radius
/ 3. * cos (G_PI
* (0.5)),
99 yc
- radius
/ 3. * sin (G_PI
* (0.5)),
100 subradius
, subradius
);
103 cairo_set_source_rgba (cr
, 0., 1., 0., alpha
);
105 xc
+ radius
/ 3. * cos (G_PI
* (0.5 + 2/.3)),
106 yc
- radius
/ 3. * sin (G_PI
* (0.5 + 2/.3)),
107 subradius
, subradius
);
110 cairo_set_source_rgba (cr
, 0., 0., 1., alpha
);
112 xc
+ radius
/ 3. * cos (G_PI
* (0.5 + 4/.3)),
113 yc
- radius
/ 3. * sin (G_PI
* (0.5 + 4/.3)),
114 subradius
, subradius
);
123 cairo_surface_t
*overlay
, *punch
, *circles
;
124 cairo_t
*overlay_cr
, *punch_cr
, *circles_cr
;
126 /* Fill the background */
127 double radius
= 0.5 * (width
< height
? width
: height
) - 10;
128 double xc
= width
/ 2.;
129 double yc
= height
/ 2.;
131 overlay
= cairo_surface_create_similar (cairo_get_target (cr
),
132 CAIRO_CONTENT_COLOR_ALPHA
,
137 punch
= cairo_surface_create_similar (cairo_get_target (cr
),
143 circles
= cairo_surface_create_similar (cairo_get_target (cr
),
144 CAIRO_CONTENT_COLOR_ALPHA
,
149 fill_checks (cr
, 0, 0, width
, height
);
151 /* Draw a black circle on the overlay
153 overlay_cr
= cairo_create (overlay
);
154 cairo_set_source_rgb (overlay_cr
, 0., 0., 0.);
155 oval_path (overlay_cr
, xc
, yc
, radius
, radius
);
156 cairo_fill (overlay_cr
);
158 /* Draw 3 circles to the punch surface, then cut
159 * that out of the main circle in the overlay
161 punch_cr
= cairo_create (punch
);
162 draw_3circles (punch_cr
, xc
, yc
, radius
, 1.0);
163 cairo_destroy (punch_cr
);
165 cairo_set_operator (overlay_cr
, CAIRO_OPERATOR_DEST_OUT
);
166 cairo_set_source_surface (overlay_cr
, punch
, 0, 0);
167 cairo_paint (overlay_cr
);
169 /* Now draw the 3 circles in a subgroup again
170 * at half intensity, and use OperatorAdd to join up
173 circles_cr
= cairo_create (circles
);
175 cairo_set_operator (circles_cr
, CAIRO_OPERATOR_OVER
);
176 draw_3circles (circles_cr
, xc
, yc
, radius
, 0.5);
177 cairo_destroy (circles_cr
);
179 cairo_set_operator (overlay_cr
, CAIRO_OPERATOR_ADD
);
180 cairo_set_source_surface (overlay_cr
, circles
, 0, 0);
181 cairo_paint (overlay_cr
);
183 cairo_destroy (overlay_cr
);
185 cairo_set_source_surface (cr
, overlay
, 0, 0);
188 cairo_surface_destroy (overlay
);
189 cairo_surface_destroy (punch
);
190 cairo_surface_destroy (circles
);
194 on_expose_event (GtkWidget
*widget
,
195 GdkEventExpose
*event
,
200 cr
= gdk_cairo_create (widget
->window
);
202 draw (cr
, widget
->allocation
.width
, widget
->allocation
.height
);
210 main (int argc
, char **argv
)
212 GtkWidget
*window
, *darea
;
214 gtk_init (&argc
, &argv
);
216 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
218 gtk_window_set_default_size (GTK_WINDOW (window
), 400, 400);
219 gtk_window_set_title (GTK_WINDOW (window
), "cairo: Knockout Groups");
221 darea
= gtk_drawing_area_new ();
222 gtk_container_add (GTK_CONTAINER (window
), darea
);
224 g_signal_connect (darea
, "expose-event",
225 G_CALLBACK (on_expose_event
), NULL
);
226 g_signal_connect (window
, "destroy-event",
227 G_CALLBACK (gtk_main_quit
), NULL
);
229 gtk_widget_show_all (window
);