]> Pileus Git - ~andy/gtk/blob - gdk/gdkcairo.c
Merge branch 'client-side-windows'
[~andy/gtk] / gdk / gdkcairo.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2005 Red Hat, Inc. 
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gdkcairo.h"
21 #include "gdkdrawable.h"
22 #include "gdkinternals.h"
23 #include "gdkregion-generic.h"
24 #include "gdkalias.h"
25
26 /**
27  * gdk_cairo_create:
28  * @drawable: a #GdkDrawable
29  * 
30  * Creates a Cairo context for drawing to @drawable.
31  *
32  * <note><para>
33  * Note that due to double-buffering, Cairo contexts created 
34  * in a GTK+ expose event handler cannot be cached and reused 
35  * between different expose events. 
36  * </para></note>
37  *
38  * Return value: A newly created Cairo context. Free with
39  *  cairo_destroy() when you are done drawing.
40  * 
41  * Since: 2.8
42  **/
43 cairo_t *
44 gdk_cairo_create (GdkDrawable *drawable)
45 {
46   cairo_surface_t *surface;
47   cairo_t *cr;
48     
49   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
50
51   surface = _gdk_drawable_ref_cairo_surface (drawable);
52   cr = cairo_create (surface);
53
54   if (GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip)
55     GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip (drawable, cr);
56     
57   cairo_surface_destroy (surface);
58
59   return cr;
60 }
61
62 /**
63  * gdk_cairo_set_source_color:
64  * @cr: a #cairo_t
65  * @color: a #GdkColor
66  * 
67  * Sets the specified #GdkColor as the source color of @cr.
68  *
69  * Since: 2.8
70  **/
71 void
72 gdk_cairo_set_source_color (cairo_t        *cr,
73                             const GdkColor *color)
74 {
75   g_return_if_fail (cr != NULL);
76   g_return_if_fail (color != NULL);
77     
78   cairo_set_source_rgb (cr,
79                         color->red / 65535.,
80                         color->green / 65535.,
81                         color->blue / 65535.);
82 }
83
84 /**
85  * gdk_cairo_rectangle:
86  * @cr: a #cairo_t
87  * @rectangle: a #GdkRectangle
88  * 
89  * Adds the given rectangle to the current path of @cr.
90  *
91  * Since: 2.8
92  **/
93 void
94 gdk_cairo_rectangle (cairo_t            *cr,
95                      const GdkRectangle *rectangle)
96 {
97   g_return_if_fail (cr != NULL);
98   g_return_if_fail (rectangle != NULL);
99
100   cairo_rectangle (cr,
101                    rectangle->x,     rectangle->y,
102                    rectangle->width, rectangle->height);
103 }
104
105 /**
106  * gdk_cairo_region:
107  * @cr: a #cairo_t
108  * @region: a #GdkRegion
109  * 
110  * Adds the given region to the current path of @cr.
111  *
112  * Since: 2.8
113  **/
114 void
115 gdk_cairo_region (cairo_t         *cr,
116                   const GdkRegion *region)
117 {
118   GdkRegionBox *boxes;
119   gint n_boxes, i;
120
121   g_return_if_fail (cr != NULL);
122   g_return_if_fail (region != NULL);
123
124   boxes = region->rects;
125   n_boxes = region->numRects;
126
127   for (i = 0; i < n_boxes; i++)
128     cairo_rectangle (cr,
129                      boxes[i].x1,
130                      boxes[i].y1,
131                      boxes[i].x2 - boxes[i].x1,
132                      boxes[i].y2 - boxes[i].y1);
133 }
134
135 /**
136  * gdk_cairo_set_source_pixbuf:
137  * @cr: a #Cairo context
138  * @pixbuf: a #GdkPixbuf
139  * @pixbuf_x: X coordinate of location to place upper left corner of @pixbuf
140  * @pixbuf_y: Y coordinate of location to place upper left corner of @pixbuf
141  * 
142  * Sets the given pixbuf as the source pattern for the Cairo context.
143  * The pattern has an extend mode of %CAIRO_EXTEND_NONE and is aligned
144  * so that the origin of @pixbuf is @pixbuf_x, @pixbuf_y
145  *
146  * Since: 2.8
147  **/
148 void
149 gdk_cairo_set_source_pixbuf (cairo_t         *cr,
150                              const GdkPixbuf *pixbuf,
151                              double           pixbuf_x,
152                              double           pixbuf_y)
153 {
154   gint width = gdk_pixbuf_get_width (pixbuf);
155   gint height = gdk_pixbuf_get_height (pixbuf);
156   guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
157   int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
158   int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
159   int cairo_stride;
160   guchar *cairo_pixels;
161   cairo_format_t format;
162   cairo_surface_t *surface;
163   static const cairo_user_data_key_t key;
164   int j;
165
166   if (n_channels == 3)
167     format = CAIRO_FORMAT_RGB24;
168   else
169     format = CAIRO_FORMAT_ARGB32;
170
171   cairo_stride = cairo_format_stride_for_width (format, width);
172   cairo_pixels = g_malloc (height * cairo_stride);
173   surface = cairo_image_surface_create_for_data ((unsigned char *)cairo_pixels,
174                                                  format,
175                                                  width, height, cairo_stride);
176
177   cairo_surface_set_user_data (surface, &key,
178                                cairo_pixels, (cairo_destroy_func_t)g_free);
179
180   for (j = height; j; j--)
181     {
182       guchar *p = gdk_pixels;
183       guchar *q = cairo_pixels;
184
185       if (n_channels == 3)
186         {
187           guchar *end = p + 3 * width;
188           
189           while (p < end)
190             {
191 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
192               q[0] = p[2];
193               q[1] = p[1];
194               q[2] = p[0];
195 #else     
196               q[1] = p[0];
197               q[2] = p[1];
198               q[3] = p[2];
199 #endif
200               p += 3;
201               q += 4;
202             }
203         }
204       else
205         {
206           guchar *end = p + 4 * width;
207           guint t1,t2,t3;
208             
209 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
210
211           while (p < end)
212             {
213 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
214               MULT(q[0], p[2], p[3], t1);
215               MULT(q[1], p[1], p[3], t2);
216               MULT(q[2], p[0], p[3], t3);
217               q[3] = p[3];
218 #else     
219               q[0] = p[3];
220               MULT(q[1], p[0], p[3], t1);
221               MULT(q[2], p[1], p[3], t2);
222               MULT(q[3], p[2], p[3], t3);
223 #endif
224               
225               p += 4;
226               q += 4;
227             }
228           
229 #undef MULT
230         }
231
232       gdk_pixels += gdk_rowstride;
233       cairo_pixels += cairo_stride;
234     }
235
236   cairo_set_source_surface (cr, surface, pixbuf_x, pixbuf_y);
237   cairo_surface_destroy (surface);
238 }
239
240 /**
241  * gdk_cairo_set_source_pixmap:
242  * @cr: a #Cairo context
243  * @pixmap: a #GdkPixmap
244  * @pixmap_x: X coordinate of location to place upper left corner of @pixmap
245  * @pixmap_y: Y coordinate of location to place upper left corner of @pixmap
246  * 
247  * Sets the given pixmap as the source pattern for the Cairo context.
248  * The pattern has an extend mode of %CAIRO_EXTEND_NONE and is aligned
249  * so that the origin of @pixmap is @pixmap_x, @pixmap_y
250  *
251  * Since: 2.10
252  **/
253 void
254 gdk_cairo_set_source_pixmap (cairo_t   *cr,
255                              GdkPixmap *pixmap,
256                              double     pixmap_x,
257                              double     pixmap_y)
258 {
259   cairo_surface_t *surface;
260   
261   surface = _gdk_drawable_ref_cairo_surface (GDK_DRAWABLE (pixmap));
262   cairo_set_source_surface (cr, surface, pixmap_x, pixmap_y);
263   cairo_surface_destroy (surface);
264 }
265
266
267 #define __GDK_CAIRO_C__
268 #include "gdkaliasdef.c"