]> Pileus Git - ~andy/gtk/blob - tests/testcairo.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / tests / testcairo.c
1 /* testimage.c
2  * Copyright (C) 2005  Red Hat, Inc.
3  * Based on cairo-demo/X11/cairo-knockout.c
4  *
5  * Author: Owen Taylor
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include <math.h>
22
23 #include <gtk/gtk.h>
24
25 static void
26 oval_path (cairo_t *cr,
27            double xc, double yc,
28            double xr, double yr)
29 {
30   cairo_save (cr);
31
32   cairo_translate (cr, xc, yc);
33   cairo_scale (cr, 1.0, yr / xr);
34   cairo_move_to (cr, xr, 0.0);
35   cairo_arc (cr,
36              0, 0,
37              xr,
38              0, 2 * G_PI);
39   cairo_close_path (cr);
40
41   cairo_restore (cr);
42 }
43
44 /* Create a path that is a circular oval with radii xr, yr at xc,
45  * yc.
46  */
47 /* Fill the given area with checks in the standard style
48  * for showing compositing effects.
49  *
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.
54  */
55 static void
56 fill_checks (cairo_t *cr,
57              int x,     int y,
58              int width, int height)
59 {
60   int i, j;
61   
62 #define CHECK_SIZE 32
63
64   cairo_rectangle (cr, x, y, width, height);
65   cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
66   cairo_fill (cr);
67
68   /* Only works for CHECK_SIZE a power of 2 */
69   j = x & (-CHECK_SIZE);
70   
71   for (; j < height; j += CHECK_SIZE)
72     {
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);
77     }
78
79   cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
80   cairo_fill (cr);
81 }
82
83 /* Draw a red, green, and blue circle equally spaced inside
84  * the larger circle of radius r at (xc, yc)
85  */
86 static void
87 draw_3circles (cairo_t *cr,
88                double xc, double yc,
89                double radius,
90                double alpha)
91 {
92   double subradius = radius * (2 / 3. - 0.1);
93     
94   cairo_set_source_rgba (cr, 1., 0., 0., alpha);
95   oval_path (cr,
96              xc + radius / 3. * cos (G_PI * (0.5)),
97              yc - radius / 3. * sin (G_PI * (0.5)),
98              subradius, subradius);
99   cairo_fill (cr);
100     
101   cairo_set_source_rgba (cr, 0., 1., 0., alpha);
102   oval_path (cr,
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);
106   cairo_fill (cr);
107     
108   cairo_set_source_rgba (cr, 0., 0., 1., alpha);
109   oval_path (cr,
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);
113   cairo_fill (cr);
114 }
115
116 static gboolean
117 on_draw (GtkWidget *widget,
118          cairo_t   *cr)
119 {
120   cairo_surface_t *overlay, *punch, *circles;
121   cairo_t *overlay_cr, *punch_cr, *circles_cr;
122
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.;
129
130   overlay = cairo_surface_create_similar (cairo_get_target (cr),
131                                           CAIRO_CONTENT_COLOR_ALPHA,
132                                           width, height);
133
134   punch = cairo_surface_create_similar (cairo_get_target (cr),
135                                         CAIRO_CONTENT_ALPHA,
136                                         width, height);
137
138   circles = cairo_surface_create_similar (cairo_get_target (cr),
139                                           CAIRO_CONTENT_COLOR_ALPHA,
140                                           width, height);
141     
142   fill_checks (cr, 0, 0, width, height);
143
144   /* Draw a black circle on the overlay
145    */
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);
150
151   /* Draw 3 circles to the punch surface, then cut
152    * that out of the main circle in the overlay
153    */
154   punch_cr = cairo_create (punch);
155   draw_3circles (punch_cr, xc, yc, radius, 1.0);
156   cairo_destroy (punch_cr);
157
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);
161
162   /* Now draw the 3 circles in a subgroup again
163    * at half intensity, and use OperatorAdd to join up
164    * without seams.
165    */
166   circles_cr = cairo_create (circles);
167   
168   cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
169   draw_3circles (circles_cr, xc, yc, radius, 0.5);
170   cairo_destroy (circles_cr);
171
172   cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
173   cairo_set_source_surface (overlay_cr, circles, 0, 0);
174   cairo_paint (overlay_cr);
175
176   cairo_destroy (overlay_cr);
177
178   cairo_set_source_surface (cr, overlay, 0, 0);
179   cairo_paint (cr);
180
181   cairo_surface_destroy (overlay);
182   cairo_surface_destroy (punch);
183   cairo_surface_destroy (circles);
184
185   return FALSE;
186 }
187
188 int
189 main (int argc, char **argv)
190 {
191   GtkWidget *window, *darea;
192
193   gtk_init (&argc, &argv);
194
195   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
196   
197   gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
198   gtk_window_set_title (GTK_WINDOW (window), "cairo: Knockout Groups");
199
200   darea = gtk_drawing_area_new ();
201   gtk_container_add (GTK_CONTAINER (window), darea);
202
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);
207
208   gtk_widget_show_all (window);
209   
210   gtk_main ();
211
212   return 0;
213 }