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, see <http://www.gnu.org/licenses/>.
26 oval_path (cairo_t *cr,
32 cairo_translate (cr, xc, yc);
33 cairo_scale (cr, 1.0, yr / xr);
34 cairo_move_to (cr, xr, 0.0);
39 cairo_close_path (cr);
44 /* Create a path that is a circular oval with radii xr, yr at xc,
47 /* Fill the given area with checks in the standard style
48 * for showing compositing effects.
50 * It would make sense to do this as a repeating surface,
51 * but most implementations of RENDER currently have broken
52 * implementations of repeat + transform, even when the
53 * transform is a translation.
56 fill_checks (cairo_t *cr,
58 int width, int height)
64 cairo_rectangle (cr, x, y, width, height);
65 cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
68 /* Only works for CHECK_SIZE a power of 2 */
69 j = x & (-CHECK_SIZE);
71 for (; j < height; j += CHECK_SIZE)
73 i = y & (-CHECK_SIZE);
74 for (; i < width; i += CHECK_SIZE)
75 if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0)
76 cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
79 cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
83 /* Draw a red, green, and blue circle equally spaced inside
84 * the larger circle of radius r at (xc, yc)
87 draw_3circles (cairo_t *cr,
92 double subradius = radius * (2 / 3. - 0.1);
94 cairo_set_source_rgba (cr, 1., 0., 0., alpha);
96 xc + radius / 3. * cos (G_PI * (0.5)),
97 yc - radius / 3. * sin (G_PI * (0.5)),
98 subradius, subradius);
101 cairo_set_source_rgba (cr, 0., 1., 0., alpha);
103 xc + radius / 3. * cos (G_PI * (0.5 + 2/.3)),
104 yc - radius / 3. * sin (G_PI * (0.5 + 2/.3)),
105 subradius, subradius);
108 cairo_set_source_rgba (cr, 0., 0., 1., alpha);
110 xc + radius / 3. * cos (G_PI * (0.5 + 4/.3)),
111 yc - radius / 3. * sin (G_PI * (0.5 + 4/.3)),
112 subradius, subradius);
117 on_draw (GtkWidget *widget,
120 cairo_surface_t *overlay, *punch, *circles;
121 cairo_t *overlay_cr, *punch_cr, *circles_cr;
123 /* Fill the background */
124 int width = gtk_widget_get_allocated_width (widget);
125 int height = gtk_widget_get_allocated_height (widget);
126 double radius = 0.5 * (width < height ? width : height) - 10;
127 double xc = width / 2.;
128 double yc = height / 2.;
130 overlay = cairo_surface_create_similar (cairo_get_target (cr),
131 CAIRO_CONTENT_COLOR_ALPHA,
134 punch = cairo_surface_create_similar (cairo_get_target (cr),
138 circles = cairo_surface_create_similar (cairo_get_target (cr),
139 CAIRO_CONTENT_COLOR_ALPHA,
142 fill_checks (cr, 0, 0, width, height);
144 /* Draw a black circle on the overlay
146 overlay_cr = cairo_create (overlay);
147 cairo_set_source_rgb (overlay_cr, 0., 0., 0.);
148 oval_path (overlay_cr, xc, yc, radius, radius);
149 cairo_fill (overlay_cr);
151 /* Draw 3 circles to the punch surface, then cut
152 * that out of the main circle in the overlay
154 punch_cr = cairo_create (punch);
155 draw_3circles (punch_cr, xc, yc, radius, 1.0);
156 cairo_destroy (punch_cr);
158 cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT);
159 cairo_set_source_surface (overlay_cr, punch, 0, 0);
160 cairo_paint (overlay_cr);
162 /* Now draw the 3 circles in a subgroup again
163 * at half intensity, and use OperatorAdd to join up
166 circles_cr = cairo_create (circles);
168 cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
169 draw_3circles (circles_cr, xc, yc, radius, 0.5);
170 cairo_destroy (circles_cr);
172 cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
173 cairo_set_source_surface (overlay_cr, circles, 0, 0);
174 cairo_paint (overlay_cr);
176 cairo_destroy (overlay_cr);
178 cairo_set_source_surface (cr, overlay, 0, 0);
181 cairo_surface_destroy (overlay);
182 cairo_surface_destroy (punch);
183 cairo_surface_destroy (circles);
189 main (int argc, char **argv)
191 GtkWidget *window, *darea;
193 gtk_init (&argc, &argv);
195 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
197 gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
198 gtk_window_set_title (GTK_WINDOW (window), "cairo: Knockout Groups");
200 darea = gtk_drawing_area_new ();
201 gtk_container_add (GTK_CONTAINER (window), darea);
203 g_signal_connect (darea, "draw",
204 G_CALLBACK (on_draw), NULL);
205 g_signal_connect (window, "destroy-event",
206 G_CALLBACK (gtk_main_quit), NULL);
208 gtk_widget_show_all (window);