]> Pileus Git - ~andy/gtk/blob - gdk/gdkdraw.c
Make GTK+ use an external gdk-pixbuf
[~andy/gtk] / gdk / gdkdraw.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <math.h>
29 #include <pango/pangocairo.h>
30 #include <gdk-pixbuf/gdk-pixbuf.h>
31 #include "gdkcairo.h"
32 #include "gdkdrawable.h"
33 #include "gdkinternals.h"
34 #include "gdkwindow.h"
35 #include "gdkscreen.h"
36 #include "gdkpixbuf.h"
37 #include "gdkalias.h"
38
39 static GdkImage*    gdk_drawable_real_get_image (GdkDrawable     *drawable,
40                                                  gint             x,
41                                                  gint             y,
42                                                  gint             width,
43                                                  gint             height);
44 static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable  *drawable,
45                                                               gint          x,
46                                                               gint          y,
47                                                               gint          width,
48                                                               gint          height,
49                                                               gint         *composite_x_offset,
50                                                               gint         *composite_y_offset);
51 static GdkRegion *  gdk_drawable_real_get_visible_region     (GdkDrawable  *drawable);
52 static void         gdk_drawable_real_draw_pixbuf            (GdkDrawable  *drawable,
53                                                               GdkGC        *gc,
54                                                               GdkPixbuf    *pixbuf,
55                                                               gint          src_x,
56                                                               gint          src_y,
57                                                               gint          dest_x,
58                                                               gint          dest_y,
59                                                               gint          width,
60                                                               gint          height,
61                                                               GdkRgbDither  dither,
62                                                               gint          x_dither,
63                                                               gint          y_dither);
64 static void         gdk_drawable_real_draw_drawable          (GdkDrawable  *drawable,
65                                                               GdkGC        *gc,
66                                                               GdkDrawable  *src,
67                                                               gint          xsrc,
68                                                               gint          ysrc,
69                                                               gint          xdest,
70                                                               gint          ydest,
71                                                               gint          width,
72                                                               gint          height);
73      
74
75 G_DEFINE_ABSTRACT_TYPE (GdkDrawable, gdk_drawable, G_TYPE_OBJECT)
76
77 static void
78 gdk_drawable_class_init (GdkDrawableClass *klass)
79 {
80   klass->get_image = gdk_drawable_real_get_image;
81   klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
82   /* Default implementation for clip and visible region is the same */
83   klass->get_clip_region = gdk_drawable_real_get_visible_region;
84   klass->get_visible_region = gdk_drawable_real_get_visible_region;
85   klass->draw_pixbuf = gdk_drawable_real_draw_pixbuf;
86   klass->draw_drawable = gdk_drawable_real_draw_drawable;
87 }
88
89 static void
90 gdk_drawable_init (GdkDrawable *drawable)
91 {
92 }
93
94 /* Manipulation of drawables
95  */
96
97 /**
98  * gdk_drawable_get_size:
99  * @drawable: a #GdkDrawable
100  * @width: (out) (allow-none): location to store drawable's width, or %NULL
101  * @height: (out) (allow-none): location to store drawable's height, or %NULL
102  *
103  * Fills *@width and *@height with the size of @drawable.
104  * @width or @height can be %NULL if you only want the other one.
105  *
106  * On the X11 platform, if @drawable is a #GdkWindow, the returned
107  * size is the size reported in the most-recently-processed configure
108  * event, rather than the current size on the X server.
109  * 
110  **/
111 void
112 gdk_drawable_get_size (GdkDrawable *drawable,
113                        gint        *width,
114                        gint        *height)
115 {
116   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
117
118   if (GDK_DRAWABLE_GET_CLASS (drawable)->get_size != NULL)
119     GDK_DRAWABLE_GET_CLASS (drawable)->get_size (drawable, width, height);  
120 }
121
122 /**
123  * gdk_drawable_get_visual:
124  * @drawable: a #GdkDrawable
125  * 
126  * Gets the #GdkVisual describing the pixel format of @drawable.
127  * 
128  * Return value: a #GdkVisual
129  **/
130 GdkVisual*
131 gdk_drawable_get_visual (GdkDrawable *drawable)
132 {
133   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
134   
135   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visual (drawable);
136 }
137
138 /**
139  * gdk_drawable_get_depth:
140  * @drawable: a #GdkDrawable
141  * 
142  * Obtains the bit depth of the drawable, that is, the number of bits
143  * that make up a pixel in the drawable's visual. Examples are 8 bits
144  * per pixel, 24 bits per pixel, etc.
145  * 
146  * Return value: number of bits per pixel
147  **/
148 gint
149 gdk_drawable_get_depth (GdkDrawable *drawable)
150 {
151   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), 0);
152
153   return GDK_DRAWABLE_GET_CLASS (drawable)->get_depth (drawable);
154 }
155 /**
156  * gdk_drawable_get_screen:
157  * @drawable: a #GdkDrawable
158  * 
159  * Gets the #GdkScreen associated with a #GdkDrawable.
160  * 
161  * Return value: the #GdkScreen associated with @drawable
162  *
163  * Since: 2.2
164  **/
165 GdkScreen*
166 gdk_drawable_get_screen(GdkDrawable *drawable)
167 {
168   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
169
170   return GDK_DRAWABLE_GET_CLASS (drawable)->get_screen (drawable);
171 }
172
173 /**
174  * gdk_drawable_get_display:
175  * @drawable: a #GdkDrawable
176  * 
177  * Gets the #GdkDisplay associated with a #GdkDrawable.
178  * 
179  * Return value: the #GdkDisplay associated with @drawable
180  *
181  * Since: 2.2
182  **/
183 GdkDisplay*
184 gdk_drawable_get_display (GdkDrawable *drawable)
185 {
186   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
187   
188   return gdk_screen_get_display (gdk_drawable_get_screen (drawable));
189 }
190         
191 /**
192  * gdk_drawable_set_colormap:
193  * @drawable: a #GdkDrawable
194  * @colormap: a #GdkColormap
195  *
196  * Sets the colormap associated with @drawable. Normally this will
197  * happen automatically when the drawable is created; you only need to
198  * use this function if the drawable-creating function did not have a
199  * way to determine the colormap, and you then use drawable operations
200  * that require a colormap. The colormap for all drawables and
201  * graphics contexts you intend to use together should match. i.e.
202  * when using a #GdkGC to draw to a drawable, or copying one drawable
203  * to another, the colormaps should match.
204  * 
205  **/
206 void
207 gdk_drawable_set_colormap (GdkDrawable *drawable,
208                            GdkColormap *cmap)
209 {
210   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
211   g_return_if_fail (cmap == NULL || gdk_drawable_get_depth (drawable)
212                     == cmap->visual->depth);
213
214   GDK_DRAWABLE_GET_CLASS (drawable)->set_colormap (drawable, cmap);
215 }
216
217 /**
218  * gdk_drawable_get_colormap:
219  * @drawable: a #GdkDrawable
220  * 
221  * Gets the colormap for @drawable, if one is set; returns
222  * %NULL otherwise.
223  * 
224  * Return value: the colormap, or %NULL
225  **/
226 GdkColormap*
227 gdk_drawable_get_colormap (GdkDrawable *drawable)
228 {
229   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
230
231   return GDK_DRAWABLE_GET_CLASS (drawable)->get_colormap (drawable);
232 }
233
234 /* Drawing
235  */
236
237 /**
238  * gdk_draw_point:
239  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
240  * @gc: a #GdkGC.
241  * @x: the x coordinate of the point.
242  * @y: the y coordinate of the point.
243  * 
244  * Draws a point, using the foreground color and other attributes of 
245  * the #GdkGC.
246  **/
247 void
248 gdk_draw_point (GdkDrawable *drawable,
249                 GdkGC       *gc,
250                 gint         x,
251                 gint         y)
252 {
253   GdkPoint point;
254
255   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
256   g_return_if_fail (GDK_IS_GC (gc));
257
258   point.x = x;
259   point.y = y;
260   
261   GDK_DRAWABLE_GET_CLASS (drawable)->draw_points (drawable, gc, &point, 1);
262 }
263
264 /**
265  * gdk_draw_line:
266  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap). 
267  * @gc: a #GdkGC.
268  * @x1_: the x coordinate of the start point.
269  * @y1_: the y coordinate of the start point.
270  * @x2_: the x coordinate of the end point.
271  * @y2_: the y coordinate of the end point.
272  * 
273  * Draws a line, using the foreground color and other attributes of 
274  * the #GdkGC.
275  **/
276 void
277 gdk_draw_line (GdkDrawable *drawable,
278                GdkGC       *gc,
279                gint         x1,
280                gint         y1,
281                gint         x2,
282                gint         y2)
283 {
284   GdkSegment segment;
285
286   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
287   g_return_if_fail (GDK_IS_GC (gc));
288
289   segment.x1 = x1;
290   segment.y1 = y1;
291   segment.x2 = x2;
292   segment.y2 = y2;
293   GDK_DRAWABLE_GET_CLASS (drawable)->draw_segments (drawable, gc, &segment, 1);
294 }
295
296 /**
297  * gdk_draw_rectangle:
298  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
299  * @gc: a #GdkGC.
300  * @filled: %TRUE if the rectangle should be filled.
301  * @x: the x coordinate of the left edge of the rectangle.
302  * @y: the y coordinate of the top edge of the rectangle.
303  * @width: the width of the rectangle.
304  * @height: the height of the rectangle.
305  * 
306  * Draws a rectangular outline or filled rectangle, using the foreground color
307  * and other attributes of the #GdkGC.
308  *
309  * A rectangle drawn filled is 1 pixel smaller in both dimensions than a 
310  * rectangle outlined. Calling 
311  * <literal>gdk_draw_rectangle (window, gc, TRUE, 0, 0, 20, 20)</literal> 
312  * results in a filled rectangle 20 pixels wide and 20 pixels high. Calling
313  * <literal>gdk_draw_rectangle (window, gc, FALSE, 0, 0, 20, 20)</literal> 
314  * results in an outlined rectangle with corners at (0, 0), (0, 20), (20, 20),
315  * and (20, 0), which makes it 21 pixels wide and 21 pixels high.
316  **/
317 void
318 gdk_draw_rectangle (GdkDrawable *drawable,
319                     GdkGC       *gc,
320                     gboolean     filled,
321                     gint         x,
322                     gint         y,
323                     gint         width,
324                     gint         height)
325 {  
326   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
327   g_return_if_fail (GDK_IS_GC (gc));
328
329   if (width < 0 || height < 0)
330     {
331       gint real_width;
332       gint real_height;
333       
334       gdk_drawable_get_size (drawable, &real_width, &real_height);
335
336       if (width < 0)
337         width = real_width;
338       if (height < 0)
339         height = real_height;
340     }
341
342   GDK_DRAWABLE_GET_CLASS (drawable)->draw_rectangle (drawable, gc, filled, x, y,
343                                                      width, height);
344 }
345
346 /**
347  * gdk_draw_arc:
348  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
349  * @gc: a #GdkGC.
350  * @filled: %TRUE if the arc should be filled, producing a 'pie slice'.
351  * @x: the x coordinate of the left edge of the bounding rectangle.
352  * @y: the y coordinate of the top edge of the bounding rectangle.
353  * @width: the width of the bounding rectangle.
354  * @height: the height of the bounding rectangle.
355  * @angle1: the start angle of the arc, relative to the 3 o'clock position,
356  *     counter-clockwise, in 1/64ths of a degree.
357  * @angle2: the end angle of the arc, relative to @angle1, in 1/64ths 
358  *     of a degree.
359  * 
360  * Draws an arc or a filled 'pie slice'. The arc is defined by the bounding
361  * rectangle of the entire ellipse, and the start and end angles of the part 
362  * of the ellipse to be drawn.
363  **/
364 void
365 gdk_draw_arc (GdkDrawable *drawable,
366               GdkGC       *gc,
367               gboolean     filled,
368               gint         x,
369               gint         y,
370               gint         width,
371               gint         height,
372               gint         angle1,
373               gint         angle2)
374 {  
375   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
376   g_return_if_fail (GDK_IS_GC (gc));
377
378   if (width < 0 || height < 0)
379     {
380       gint real_width;
381       gint real_height;
382       
383       gdk_drawable_get_size (drawable, &real_width, &real_height);
384
385       if (width < 0)
386         width = real_width;
387       if (height < 0)
388         height = real_height;
389     }
390
391   GDK_DRAWABLE_GET_CLASS (drawable)->draw_arc (drawable, gc, filled,
392                                                x, y, width, height, angle1, angle2);
393 }
394
395 /**
396  * gdk_draw_polygon:
397  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
398  * @gc: a #GdkGC.
399  * @filled: %TRUE if the polygon should be filled. The polygon is closed
400  *     automatically, connecting the last point to the first point if 
401  *     necessary.
402  * @points: an array of #GdkPoint structures specifying the points making 
403  *     up the polygon.
404  * @n_points: the number of points.
405  * 
406  * Draws an outlined or filled polygon.
407  **/
408 void
409 gdk_draw_polygon (GdkDrawable    *drawable,
410                   GdkGC          *gc,
411                   gboolean        filled,
412                   const GdkPoint *points,
413                   gint            n_points)
414 {
415   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
416   g_return_if_fail (GDK_IS_GC (gc));
417
418   GDK_DRAWABLE_GET_CLASS (drawable)->draw_polygon (drawable, gc, filled,
419                                                    (GdkPoint *) points,
420                                                    n_points);
421 }
422
423 /**
424  * gdk_draw_drawable:
425  * @drawable: a #GdkDrawable
426  * @gc: a #GdkGC sharing the drawable's visual and colormap
427  * @src: the source #GdkDrawable, which may be the same as @drawable
428  * @xsrc: X position in @src of rectangle to draw
429  * @ysrc: Y position in @src of rectangle to draw
430  * @xdest: X position in @drawable where the rectangle should be drawn
431  * @ydest: Y position in @drawable where the rectangle should be drawn
432  * @width: width of rectangle to draw, or -1 for entire @src width
433  * @height: height of rectangle to draw, or -1 for entire @src height
434  *
435  * Copies the @width x @height region of @src at coordinates (@xsrc,
436  * @ysrc) to coordinates (@xdest, @ydest) in @drawable.
437  * @width and/or @height may be given as -1, in which case the entire
438  * @src drawable will be copied.
439  *
440  * Most fields in @gc are not used for this operation, but notably the
441  * clip mask or clip region will be honored.
442  *
443  * The source and destination drawables must have the same visual and
444  * colormap, or errors will result. (On X11, failure to match
445  * visual/colormap results in a BadMatch error from the X server.)
446  * A common cause of this problem is an attempt to draw a bitmap to
447  * a color drawable. The way to draw a bitmap is to set the bitmap as 
448  * the stipple on the #GdkGC, set the fill mode to %GDK_STIPPLED, and 
449  * then draw the rectangle.
450  **/
451 void
452 gdk_draw_drawable (GdkDrawable *drawable,
453                    GdkGC       *gc,
454                    GdkDrawable *src,
455                    gint         xsrc,
456                    gint         ysrc,
457                    gint         xdest,
458                    gint         ydest,
459                    gint         width,
460                    gint         height)
461 {
462   GdkDrawable *composite;
463   gint composite_x_offset = 0;
464   gint composite_y_offset = 0;
465
466   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
467   g_return_if_fail (GDK_IS_DRAWABLE (src));
468   g_return_if_fail (GDK_IS_GC (gc));
469
470   if (width < 0 || height < 0)
471     {
472       gint real_width;
473       gint real_height;
474       
475       gdk_drawable_get_size (src, &real_width, &real_height);
476
477       if (width < 0)
478         width = real_width;
479       if (height < 0)
480         height = real_height;
481     }
482
483
484   composite =
485     GDK_DRAWABLE_GET_CLASS (src)->get_composite_drawable (src,
486                                                           xsrc, ysrc,
487                                                           width, height,
488                                                           &composite_x_offset,
489                                                           &composite_y_offset);
490
491   /* TODO: For non-native windows this may copy stuff from other overlapping
492      windows. We should clip that and (for windows with bg != None) clear that
493      area in the destination instead. */
494
495   if (GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src)
496     GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src (drawable, gc,
497                                                                composite,
498                                                                xsrc - composite_x_offset,
499                                                                ysrc - composite_y_offset,
500                                                                xdest, ydest,
501                                                                width, height,
502                                                                src);
503   else /* backwards compat for old out-of-tree implementations of GdkDrawable (are there any?) */
504     GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc,
505                                                       composite,
506                                                       xsrc - composite_x_offset,
507                                                       ysrc - composite_y_offset,
508                                                       xdest, ydest,
509                                                       width, height);
510
511   g_object_unref (composite);
512 }
513
514 /**
515  * gdk_draw_image:
516  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
517  * @gc: a #GdkGC.
518  * @image: the #GdkImage to draw.
519  * @xsrc: the left edge of the source rectangle within @image.
520  * @ysrc: the top of the source rectangle within @image.
521  * @xdest: the x coordinate of the destination within @drawable.
522  * @ydest: the y coordinate of the destination within @drawable.
523  * @width: the width of the area to be copied, or -1 to make the area 
524  *     extend to the right edge of @image.
525  * @height: the height of the area to be copied, or -1 to make the area 
526  *     extend to the bottom edge of @image.
527  * 
528  * Draws a #GdkImage onto a drawable.
529  * The depth of the #GdkImage must match the depth of the #GdkDrawable.
530  **/
531 void
532 gdk_draw_image (GdkDrawable *drawable,
533                 GdkGC       *gc,
534                 GdkImage    *image,
535                 gint         xsrc,
536                 gint         ysrc,
537                 gint         xdest,
538                 gint         ydest,
539                 gint         width,
540                 gint         height)
541 {
542   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
543   g_return_if_fail (GDK_IS_IMAGE (image));
544   g_return_if_fail (GDK_IS_GC (gc));
545
546   if (width == -1)
547     width = image->width;
548   if (height == -1)
549     height = image->height;
550
551   GDK_DRAWABLE_GET_CLASS (drawable)->draw_image (drawable, gc, image, xsrc, ysrc,
552                                                  xdest, ydest, width, height);
553 }
554
555 /**
556  * gdk_draw_pixbuf:
557  * @drawable: Destination drawable.
558  * @gc: (allow-none): a #GdkGC, used for clipping, or %NULL
559  * @pixbuf: a #GdkPixbuf
560  * @src_x: Source X coordinate within pixbuf.
561  * @src_y: Source Y coordinates within pixbuf.
562  * @dest_x: Destination X coordinate within drawable.
563  * @dest_y: Destination Y coordinate within drawable.
564  * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
565  * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
566  * @dither: Dithering mode for #GdkRGB.
567  * @x_dither: X offset for dither.
568  * @y_dither: Y offset for dither.
569  * 
570  * Renders a rectangular portion of a pixbuf to a drawable.  The destination
571  * drawable must have a colormap. All windows have a colormap, however, pixmaps
572  * only have colormap by default if they were created with a non-%NULL window 
573  * argument. Otherwise a colormap must be set on them with 
574  * gdk_drawable_set_colormap().
575  *
576  * On older X servers, rendering pixbufs with an alpha channel involves round 
577  * trips to the X server, and may be somewhat slow.
578  *
579  * If GDK is built with the Sun mediaLib library, the gdk_draw_pixbuf
580  * function is accelerated using mediaLib, which provides hardware
581  * acceleration on Intel, AMD, and Sparc chipsets.  If desired, mediaLib
582  * support can be turned off by setting the GDK_DISABLE_MEDIALIB environment
583  * variable.
584  *
585  * Since: 2.2
586  **/
587 void
588 gdk_draw_pixbuf (GdkDrawable     *drawable,
589                  GdkGC           *gc,
590                  const GdkPixbuf *pixbuf,
591                  gint             src_x,
592                  gint             src_y,
593                  gint             dest_x,
594                  gint             dest_y,
595                  gint             width,
596                  gint             height,
597                  GdkRgbDither     dither,
598                  gint             x_dither,
599                  gint             y_dither)
600 {
601   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
602   g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
603   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
604
605   if (width == 0 || height == 0)
606     return;
607
608   if (width == -1)
609     width = gdk_pixbuf_get_width (pixbuf);
610   if (height == -1)
611     height = gdk_pixbuf_get_height (pixbuf);
612
613   GDK_DRAWABLE_GET_CLASS (drawable)->draw_pixbuf (drawable, gc,
614                                                   (GdkPixbuf *) pixbuf,
615                                                   src_x, src_y, dest_x, dest_y,
616                                                   width, height,
617                                                   dither, x_dither, y_dither);
618 }
619
620 /**
621  * gdk_draw_points:
622  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
623  * @gc: a #GdkGC.
624  * @points: an array of #GdkPoint structures.
625  * @n_points: the number of points to be drawn.
626  * 
627  * Draws a number of points, using the foreground color and other 
628  * attributes of the #GdkGC.
629  **/
630 void
631 gdk_draw_points (GdkDrawable    *drawable,
632                  GdkGC          *gc,
633                  const GdkPoint *points,
634                  gint            n_points)
635 {
636   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
637   g_return_if_fail ((points != NULL) && (n_points > 0));
638   g_return_if_fail (GDK_IS_GC (gc));
639   g_return_if_fail (n_points >= 0);
640
641   if (n_points == 0)
642     return;
643
644   GDK_DRAWABLE_GET_CLASS (drawable)->draw_points (drawable, gc,
645                                                   (GdkPoint *) points, n_points);
646 }
647
648 /**
649  * gdk_draw_segments:
650  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
651  * @gc: a #GdkGC.
652  * @segs: an array of #GdkSegment structures specifying the start and 
653  *   end points of the lines to be drawn.
654  * @n_segs: the number of line segments to draw, i.e. the size of the 
655  *   @segs array.
656  * 
657  * Draws a number of unconnected lines.
658  **/
659 void
660 gdk_draw_segments (GdkDrawable      *drawable,
661                    GdkGC            *gc,
662                    const GdkSegment *segs,
663                    gint              n_segs)
664 {
665   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
666
667   if (n_segs == 0)
668     return;
669
670   g_return_if_fail (segs != NULL);
671   g_return_if_fail (GDK_IS_GC (gc));
672   g_return_if_fail (n_segs >= 0);
673
674   GDK_DRAWABLE_GET_CLASS (drawable)->draw_segments (drawable, gc,
675                                                     (GdkSegment *) segs, n_segs);
676 }
677
678 /**
679  * gdk_draw_lines:
680  * @drawable: a #GdkDrawable (a #GdkWindow or a #GdkPixmap).
681  * @gc: a #GdkGC.
682  * @points: an array of #GdkPoint structures specifying the endpoints of the
683  * @n_points: the size of the @points array.
684  * 
685  * Draws a series of lines connecting the given points.
686  * The way in which joins between lines are draw is determined by the
687  * #GdkCapStyle value in the #GdkGC. This can be set with
688  * gdk_gc_set_line_attributes().
689  **/
690 void
691 gdk_draw_lines (GdkDrawable    *drawable,
692                 GdkGC          *gc,
693                 const GdkPoint *points,
694                 gint            n_points)
695 {
696   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
697   g_return_if_fail (points != NULL);
698   g_return_if_fail (GDK_IS_GC (gc));
699   g_return_if_fail (n_points >= 0);
700
701   if (n_points == 0)
702     return;
703
704   GDK_DRAWABLE_GET_CLASS (drawable)->draw_lines (drawable, gc,
705                                                  (GdkPoint *) points, n_points);
706 }
707
708 static void
709 real_draw_glyphs (GdkDrawable       *drawable,
710                   GdkGC             *gc,
711                   const PangoMatrix *matrix,
712                   PangoFont         *font,
713                   gdouble            x,
714                   gdouble            y,
715                   PangoGlyphString  *glyphs)
716 {
717   cairo_t *cr;
718
719   cr = gdk_cairo_create (drawable);
720   _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable);
721
722   if (matrix)
723     {
724       cairo_matrix_t cairo_matrix;
725
726       cairo_matrix.xx = matrix->xx;
727       cairo_matrix.yx = matrix->yx;
728       cairo_matrix.xy = matrix->xy;
729       cairo_matrix.yy = matrix->yy;
730       cairo_matrix.x0 = matrix->x0;
731       cairo_matrix.y0 = matrix->y0;
732       
733       cairo_set_matrix (cr, &cairo_matrix);
734     }
735
736   cairo_move_to (cr, x, y);
737   pango_cairo_show_glyph_string (cr, font, glyphs);
738
739   cairo_destroy (cr);
740 }
741
742 /**
743  * gdk_draw_glyphs:
744  * @drawable: a #GdkDrawable
745  * @gc: a #GdkGC
746  * @font: font to be used
747  * @x: X coordinate of baseline origin
748  * @y: Y coordinate of baseline origin
749  * @glyphs: the glyph string to draw
750  *
751  * This is a low-level function; 99% of text rendering should be done
752  * using gdk_draw_layout() instead.
753  *
754  * A glyph is a single image in a font. This function draws a sequence of
755  * glyphs.  To obtain a sequence of glyphs you have to understand a
756  * lot about internationalized text handling, which you don't want to
757  * understand; thus, use gdk_draw_layout() instead of this function,
758  * gdk_draw_layout() handles the details.
759  * 
760  **/
761 void
762 gdk_draw_glyphs (GdkDrawable      *drawable,
763                  GdkGC            *gc,
764                  PangoFont        *font,
765                  gint              x,
766                  gint              y,
767                  PangoGlyphString *glyphs)
768 {
769   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
770   g_return_if_fail (GDK_IS_GC (gc));
771   
772   real_draw_glyphs (drawable, gc, NULL, font,
773                     x, y, glyphs);
774 }
775
776 /**
777  * gdk_draw_glyphs_transformed:
778  * @drawable: a #GdkDrawable
779  * @gc: a #GdkGC
780  * @matrix: (allow-none): a #PangoMatrix, or %NULL to use an identity transformation
781  * @font: the font in which to draw the string
782  * @x:       the x position of the start of the string (in Pango
783  *           units in user space coordinates)
784  * @y:       the y position of the baseline (in Pango units
785  *           in user space coordinates)
786  * @glyphs:  the glyph string to draw
787  * 
788  * Renders a #PangoGlyphString onto a drawable, possibly
789  * transforming the layed-out coordinates through a transformation
790  * matrix. Note that the transformation matrix for @font is not
791  * changed, so to produce correct rendering results, the @font
792  * must have been loaded using a #PangoContext with an identical
793  * transformation matrix to that passed in to this function.
794  *
795  * See also gdk_draw_glyphs(), gdk_draw_layout().
796  *
797  * Since: 2.6
798  **/
799 void
800 gdk_draw_glyphs_transformed (GdkDrawable       *drawable,
801                              GdkGC             *gc,
802                              const PangoMatrix *matrix,
803                              PangoFont         *font,
804                              gint               x,
805                              gint               y,
806                              PangoGlyphString  *glyphs)
807 {
808   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
809   g_return_if_fail (GDK_IS_GC (gc));
810
811   real_draw_glyphs (drawable, gc, matrix, font,
812                     x / PANGO_SCALE, y / PANGO_SCALE, glyphs);
813 }
814
815 /**
816  * gdk_draw_trapezoids:
817  * @drawable: a #GdkDrawable
818  * @gc: a #GdkGC
819  * @trapezoids: an array of #GdkTrapezoid structures
820  * @n_trapezoids: the number of trapezoids to draw
821  * 
822  * Draws a set of anti-aliased trapezoids. The trapezoids are
823  * combined using saturation addition, then drawn over the background
824  * as a set. This is low level functionality used internally to implement
825  * rotated underlines and backgrouds when rendering a PangoLayout and is
826  * likely not useful for applications.
827  *
828  * Since: 2.6
829  **/
830 void
831 gdk_draw_trapezoids (GdkDrawable        *drawable,
832                      GdkGC              *gc,
833                      const GdkTrapezoid *trapezoids,
834                      gint                n_trapezoids)
835 {
836   cairo_t *cr;
837   int i;
838
839   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
840   g_return_if_fail (GDK_IS_GC (gc));
841   g_return_if_fail (n_trapezoids == 0 || trapezoids != NULL);
842
843   cr = gdk_cairo_create (drawable);
844   _gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable);
845   
846   for (i = 0; i < n_trapezoids; i++)
847     {
848       cairo_move_to (cr, trapezoids[i].x11, trapezoids[i].y1);
849       cairo_line_to (cr, trapezoids[i].x21, trapezoids[i].y1);
850       cairo_line_to (cr, trapezoids[i].x22, trapezoids[i].y2);
851       cairo_line_to (cr, trapezoids[i].x12, trapezoids[i].y2);
852       cairo_close_path (cr);
853     }
854
855   cairo_fill (cr);
856
857   cairo_destroy (cr);
858 }
859
860 /**
861  * gdk_drawable_copy_to_image:
862  * @drawable: a #GdkDrawable
863  * @image: (allow-none): a #GdkDrawable, or %NULL if a new @image should be created.
864  * @src_x: x coordinate on @drawable
865  * @src_y: y coordinate on @drawable
866  * @dest_x: x coordinate within @image. Must be 0 if @image is %NULL
867  * @dest_y: y coordinate within @image. Must be 0 if @image is %NULL
868  * @width: width of region to get
869  * @height: height or region to get
870  *
871  * Copies a portion of @drawable into the client side image structure
872  * @image. If @image is %NULL, creates a new image of size @width x @height
873  * and copies into that. See gdk_drawable_get_image() for further details.
874  * 
875  * Return value: @image, or a new a #GdkImage containing the contents
876  *               of @drawable
877  * 
878  * Since: 2.4
879  **/
880 GdkImage*
881 gdk_drawable_copy_to_image (GdkDrawable *drawable,
882                             GdkImage    *image,
883                             gint         src_x,
884                             gint         src_y,
885                             gint         dest_x,
886                             gint         dest_y,
887                             gint         width,
888                             gint         height)
889 {
890   GdkDrawable *composite;
891   gint composite_x_offset = 0;
892   gint composite_y_offset = 0;
893   GdkImage *retval;
894   GdkColormap *cmap;
895   
896   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
897   g_return_val_if_fail (src_x >= 0, NULL);
898   g_return_val_if_fail (src_y >= 0, NULL);
899
900   /* FIXME? Note race condition since we get the size then
901    * get the image, and the size may have changed.
902    */
903   
904   if (width < 0 || height < 0)
905     gdk_drawable_get_size (drawable,
906                            width < 0 ? &width : NULL,
907                            height < 0 ? &height : NULL);
908   
909   composite =
910     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
911                                                                src_x, src_y,
912                                                                width, height,
913                                                                &composite_x_offset,
914                                                                &composite_y_offset); 
915   
916   retval = GDK_DRAWABLE_GET_CLASS (composite)->_copy_to_image (composite,
917                                                                image,
918                                                                src_x - composite_x_offset,
919                                                                src_y - composite_y_offset,
920                                                                dest_x, dest_y,
921                                                                width, height);
922
923   g_object_unref (composite);
924
925   if (!image && retval)
926     {
927       cmap = gdk_drawable_get_colormap (drawable);
928       
929       if (cmap)
930         gdk_image_set_colormap (retval, cmap);
931     }
932   
933   return retval;
934 }
935
936 /**
937  * gdk_drawable_get_image:
938  * @drawable: a #GdkDrawable
939  * @x: x coordinate on @drawable
940  * @y: y coordinate on @drawable
941  * @width: width of region to get
942  * @height: height or region to get
943  * 
944  * A #GdkImage stores client-side image data (pixels). In contrast,
945  * #GdkPixmap and #GdkWindow are server-side
946  * objects. gdk_drawable_get_image() obtains the pixels from a
947  * server-side drawable as a client-side #GdkImage.  The format of a
948  * #GdkImage depends on the #GdkVisual of the current display, which
949  * makes manipulating #GdkImage extremely difficult; therefore, in
950  * most cases you should use gdk_pixbuf_get_from_drawable() instead of
951  * this lower-level function. A #GdkPixbuf contains image data in a
952  * canonicalized RGB format, rather than a display-dependent format.
953  * Of course, there's a convenience vs. speed tradeoff here, so you'll
954  * want to think about what makes sense for your application.
955  *
956  * @x, @y, @width, and @height define the region of @drawable to
957  * obtain as an image.
958  *
959  * You would usually copy image data to the client side if you intend
960  * to examine the values of individual pixels, for example to darken
961  * an image or add a red tint. It would be prohibitively slow to
962  * make a round-trip request to the windowing system for each pixel,
963  * so instead you get all of them at once, modify them, then copy
964  * them all back at once.
965  *
966  * If the X server or other windowing system backend is on the local
967  * machine, this function may use shared memory to avoid copying
968  * the image data.
969  *
970  * If the source drawable is a #GdkWindow and partially offscreen
971  * or obscured, then the obscured portions of the returned image
972  * will contain undefined data.
973  * 
974  * Return value: a #GdkImage containing the contents of @drawable
975  **/
976 GdkImage*
977 gdk_drawable_get_image (GdkDrawable *drawable,
978                         gint         x,
979                         gint         y,
980                         gint         width,
981                         gint         height)
982 {
983   GdkDrawable *composite;
984   gint composite_x_offset = 0;
985   gint composite_y_offset = 0;
986   GdkImage *retval;
987   GdkColormap *cmap;
988   
989   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
990   g_return_val_if_fail (x >= 0, NULL);
991   g_return_val_if_fail (y >= 0, NULL);
992
993   /* FIXME? Note race condition since we get the size then
994    * get the image, and the size may have changed.
995    */
996   
997   if (width < 0 || height < 0)
998     gdk_drawable_get_size (drawable,
999                            width < 0 ? &width : NULL,
1000                            height < 0 ? &height : NULL);
1001   
1002   composite =
1003     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
1004                                                                x, y,
1005                                                                width, height,
1006                                                                &composite_x_offset,
1007                                                                &composite_y_offset); 
1008   
1009   retval = GDK_DRAWABLE_GET_CLASS (composite)->get_image (composite,
1010                                                           x - composite_x_offset,
1011                                                           y - composite_y_offset,
1012                                                           width, height);
1013
1014   g_object_unref (composite);
1015
1016   cmap = gdk_drawable_get_colormap (drawable);
1017   
1018   if (retval && cmap)
1019     gdk_image_set_colormap (retval, cmap);
1020   
1021   return retval;
1022 }
1023
1024 static GdkImage*
1025 gdk_drawable_real_get_image (GdkDrawable     *drawable,
1026                              gint             x,
1027                              gint             y,
1028                              gint             width,
1029                              gint             height)
1030 {
1031   return gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
1032 }
1033
1034 static GdkDrawable *
1035 gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
1036                                           gint         x,
1037                                           gint         y,
1038                                           gint         width,
1039                                           gint         height,
1040                                           gint        *composite_x_offset,
1041                                           gint        *composite_y_offset)
1042 {
1043   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1044
1045   *composite_x_offset = 0;
1046   *composite_y_offset = 0;
1047   
1048   return g_object_ref (drawable);
1049 }
1050
1051 /**
1052  * gdk_drawable_get_clip_region:
1053  * @drawable: a #GdkDrawable
1054  * 
1055  * Computes the region of a drawable that potentially can be written
1056  * to by drawing primitives. This region will not take into account
1057  * the clip region for the GC, and may also not take into account
1058  * other factors such as if the window is obscured by other windows,
1059  * but no area outside of this region will be affected by drawing
1060  * primitives.
1061  * 
1062  * Returns: a #GdkRegion. This must be freed with gdk_region_destroy()
1063  *          when you are done.
1064  **/
1065 GdkRegion *
1066 gdk_drawable_get_clip_region (GdkDrawable *drawable)
1067 {
1068   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1069
1070   return GDK_DRAWABLE_GET_CLASS (drawable)->get_clip_region (drawable);
1071 }
1072
1073 /**
1074  * gdk_drawable_get_visible_region:
1075  * @drawable: a #GdkDrawable
1076  * 
1077  * Computes the region of a drawable that is potentially visible.
1078  * This does not necessarily take into account if the window is
1079  * obscured by other windows, but no area outside of this region
1080  * is visible.
1081  * 
1082  * Returns: a #GdkRegion. This must be freed with gdk_region_destroy()
1083  *          when you are done.
1084  **/
1085 GdkRegion *
1086 gdk_drawable_get_visible_region (GdkDrawable *drawable)
1087 {
1088   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1089
1090   return GDK_DRAWABLE_GET_CLASS (drawable)->get_visible_region (drawable);
1091 }
1092
1093 static GdkRegion *
1094 gdk_drawable_real_get_visible_region (GdkDrawable *drawable)
1095 {
1096   GdkRectangle rect;
1097
1098   rect.x = 0;
1099   rect.y = 0;
1100
1101   gdk_drawable_get_size (drawable, &rect.width, &rect.height);
1102
1103   return gdk_region_rectangle (&rect);
1104 }
1105
1106 /**
1107  * _gdk_drawable_ref_cairo_surface:
1108  * @drawable: a #GdkDrawable
1109  * 
1110  * Obtains a #cairo_surface_t for the given drawable. If a
1111  * #cairo_surface_t for the drawable already exists, it will be
1112  * referenced, otherwise a new surface will be created.
1113  * 
1114  * Return value: a newly referenced #cairo_surface_t that points
1115  *  to @drawable. Unref with cairo_surface_destroy()
1116  **/
1117 cairo_surface_t *
1118 _gdk_drawable_ref_cairo_surface (GdkDrawable *drawable)
1119 {
1120   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1121
1122   return GDK_DRAWABLE_GET_CLASS (drawable)->ref_cairo_surface (drawable);
1123 }
1124
1125 static void
1126 composite (guchar *src_buf,
1127            gint    src_rowstride,
1128            guchar *dest_buf,
1129            gint    dest_rowstride,
1130            gint    width,
1131            gint    height)
1132 {
1133   guchar *src = src_buf;
1134   guchar *dest = dest_buf;
1135
1136   while (height--)
1137     {
1138       gint twidth = width;
1139       guchar *p = src;
1140       guchar *q = dest;
1141
1142       while (twidth--)
1143         {
1144           guchar a = p[3];
1145           guint t;
1146
1147           t = a * p[0] + (255 - a) * q[0] + 0x80;
1148           q[0] = (t + (t >> 8)) >> 8;
1149           t = a * p[1] + (255 - a) * q[1] + 0x80;
1150           q[1] = (t + (t >> 8)) >> 8;
1151           t = a * p[2] + (255 - a) * q[2] + 0x80;
1152           q[2] = (t + (t >> 8)) >> 8;
1153
1154           p += 4;
1155           q += 3;
1156         }
1157       
1158       src += src_rowstride;
1159       dest += dest_rowstride;
1160     }
1161 }
1162
1163 static void
1164 composite_0888 (guchar      *src_buf,
1165                 gint         src_rowstride,
1166                 guchar      *dest_buf,
1167                 gint         dest_rowstride,
1168                 GdkByteOrder dest_byte_order,
1169                 gint         width,
1170                 gint         height)
1171 {
1172   guchar *src = src_buf;
1173   guchar *dest = dest_buf;
1174
1175   while (height--)
1176     {
1177       gint twidth = width;
1178       guchar *p = src;
1179       guchar *q = dest;
1180
1181       if (dest_byte_order == GDK_LSB_FIRST)
1182         {
1183           while (twidth--)
1184             {
1185               guint t;
1186               
1187               t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80;
1188               q[0] = (t + (t >> 8)) >> 8;
1189               t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80;
1190               q[1] = (t + (t >> 8)) >> 8;
1191               t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80;
1192               q[2] = (t + (t >> 8)) >> 8;
1193               p += 4;
1194               q += 4;
1195             }
1196         }
1197       else
1198         {
1199           while (twidth--)
1200             {
1201               guint t;
1202               
1203               t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80;
1204               q[1] = (t + (t >> 8)) >> 8;
1205               t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80;
1206               q[2] = (t + (t >> 8)) >> 8;
1207               t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80;
1208               q[3] = (t + (t >> 8)) >> 8;
1209               p += 4;
1210               q += 4;
1211             }
1212         }
1213       
1214       src += src_rowstride;
1215       dest += dest_rowstride;
1216     }
1217 }
1218
1219 #ifdef USE_MEDIALIB
1220 static void
1221 composite_0888_medialib (guchar      *src_buf,
1222                          gint         src_rowstride,
1223                          guchar      *dest_buf,
1224                          gint         dest_rowstride,
1225                          GdkByteOrder dest_byte_order,
1226                          gint         width,
1227                          gint         height)
1228 {
1229   guchar *src  = src_buf;
1230   guchar *dest = dest_buf;
1231
1232   mlib_image img_src, img_dst;
1233
1234   mlib_ImageSetStruct (&img_dst,
1235                        MLIB_BYTE,
1236                        4,
1237                        width,
1238                        height,
1239                        dest_rowstride,
1240                        dest_buf);
1241
1242   mlib_ImageSetStruct (&img_src,
1243                        MLIB_BYTE,
1244                        4,
1245                        width,
1246                        height,
1247                        src_rowstride,
1248                        src_buf);
1249
1250   if (dest_byte_order == GDK_LSB_FIRST)
1251       mlib_ImageBlendRGBA2BGRA (&img_dst, &img_src);
1252   else
1253       mlib_ImageBlendRGBA2ARGB (&img_dst, &img_src);
1254 }
1255 #endif
1256
1257 static void
1258 composite_565 (guchar      *src_buf,
1259                gint         src_rowstride,
1260                guchar      *dest_buf,
1261                gint         dest_rowstride,
1262                GdkByteOrder dest_byte_order,
1263                gint         width,
1264                gint         height)
1265 {
1266   guchar *src = src_buf;
1267   guchar *dest = dest_buf;
1268
1269   while (height--)
1270     {
1271       gint twidth = width;
1272       guchar *p = src;
1273       gushort *q = (gushort *)dest;
1274
1275       while (twidth--)
1276         {
1277           guchar a = p[3];
1278           guint tr, tg, tb;
1279           guint tr1, tg1, tb1;
1280           guint tmp = *q;
1281
1282 #if 1
1283           /* This is fast, and corresponds to what composite() above does
1284            * if we converted to 8-bit first.
1285            */
1286           tr = (tmp & 0xf800);
1287           tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1288           tg = (tmp & 0x07e0);
1289           tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1290           tb = (tmp & 0x001f);
1291           tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1292
1293           *q = (((tr1 + (tr1 >> 8)) & 0xf800) |
1294                 (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5)  |
1295                 ((tb1 + (tb1 >> 8)) >> 11));
1296 #else
1297           /* This version correspond to the result we get with XRENDER -
1298            * a bit of precision is lost since we convert to 8 bit after premultiplying
1299            * instead of at the end
1300            */
1301           guint tr2, tg2, tb2;
1302           guint tr3, tg3, tb3;
1303           
1304           tr = (tmp & 0xf800);
1305           tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80;
1306           tr2 = a * p[0] + 0x80;
1307           tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8);
1308
1309           tg = (tmp & 0x07e0);
1310           tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80;
1311           tg2 = a * p[0] + 0x80;
1312           tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8);
1313
1314           tb = (tmp & 0x001f);
1315           tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80;
1316           tb2 = a * p[0] + 0x80;
1317           tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8);
1318
1319           *q = (((tr3 & 0xf8) << 8) |
1320                 ((tg3 & 0xfc) << 3) |
1321                 ((tb3 >> 3)));
1322 #endif
1323           
1324           p += 4;
1325           q++;
1326         }
1327       
1328       src += src_rowstride;
1329       dest += dest_rowstride;
1330     }
1331 }
1332
1333 /* Implementation of the old vfunc in terms of the new one
1334    in case someone calls it directly (which they shouldn't!) */
1335 static void
1336 gdk_drawable_real_draw_drawable (GdkDrawable  *drawable,
1337                                  GdkGC         *gc,
1338                                  GdkDrawable  *src,
1339                                  gint           xsrc,
1340                                  gint           ysrc,
1341                                  gint           xdest,
1342                                  gint           ydest,
1343                                  gint           width,
1344                                  gint           height)
1345 {
1346   GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable_with_src (drawable,
1347                                                              gc,
1348                                                              src,
1349                                                              xsrc,
1350                                                              ysrc,
1351                                                              xdest,
1352                                                              ydest,
1353                                                              width,
1354                                                              height,
1355                                                              src);
1356 }
1357
1358 static void
1359 gdk_drawable_real_draw_pixbuf (GdkDrawable  *drawable,
1360                                GdkGC        *gc,
1361                                GdkPixbuf    *pixbuf,
1362                                gint          src_x,
1363                                gint          src_y,
1364                                gint          dest_x,
1365                                gint          dest_y,
1366                                gint          width,
1367                                gint          height,
1368                                GdkRgbDither  dither,
1369                                gint          x_dither,
1370                                gint          y_dither)
1371 {
1372   GdkPixbuf *composited = NULL;
1373   gint dwidth, dheight;
1374   GdkRegion *clip;
1375   GdkRegion *drect;
1376   GdkRectangle tmp_rect;
1377   GdkDrawable  *real_drawable;
1378
1379   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1380   g_return_if_fail (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
1381   g_return_if_fail (gdk_pixbuf_get_n_channels (pixbuf) == 3 ||
1382                     gdk_pixbuf_get_n_channels (pixbuf) == 4);
1383   g_return_if_fail (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
1384
1385   g_return_if_fail (drawable != NULL);
1386
1387   if (width == -1) 
1388     width = gdk_pixbuf_get_width (pixbuf);
1389   if (height == -1)
1390     height = gdk_pixbuf_get_height (pixbuf);
1391
1392   g_return_if_fail (width >= 0 && height >= 0);
1393   g_return_if_fail (src_x >= 0 && src_x + width <= gdk_pixbuf_get_width (pixbuf));
1394   g_return_if_fail (src_y >= 0 && src_y + height <= gdk_pixbuf_get_height (pixbuf));
1395
1396   /* Clip to the drawable; this is required for get_from_drawable() so
1397    * can't be done implicitly
1398    */
1399   
1400   if (dest_x < 0)
1401     {
1402       src_x -= dest_x;
1403       width += dest_x;
1404       dest_x = 0;
1405     }
1406
1407   if (dest_y < 0)
1408     {
1409       src_y -= dest_y;
1410       height += dest_y;
1411       dest_y = 0;
1412     }
1413
1414   gdk_drawable_get_size (drawable, &dwidth, &dheight);
1415
1416   if ((dest_x + width) > dwidth)
1417     width = dwidth - dest_x;
1418
1419   if ((dest_y + height) > dheight)
1420     height = dheight - dest_y;
1421
1422   if (width <= 0 || height <= 0)
1423     return;
1424
1425   /* Clip to the clip region; this avoids getting more
1426    * image data from the server than we need to.
1427    */
1428   
1429   tmp_rect.x = dest_x;
1430   tmp_rect.y = dest_y;
1431   tmp_rect.width = width;
1432   tmp_rect.height = height;
1433
1434   drect = gdk_region_rectangle (&tmp_rect);
1435   clip = gdk_drawable_get_clip_region (drawable);
1436
1437   gdk_region_intersect (drect, clip);
1438
1439   gdk_region_get_clipbox (drect, &tmp_rect);
1440   
1441   gdk_region_destroy (drect);
1442   gdk_region_destroy (clip);
1443
1444   if (tmp_rect.width == 0 ||
1445       tmp_rect.height == 0)
1446     return;
1447   
1448   /* Actually draw */
1449   if (!gc)
1450     gc = _gdk_drawable_get_scratch_gc (drawable, FALSE);
1451
1452   /* Drawable is a wrapper here, but at this time we
1453      have already retargeted the destination to any
1454      impl window and set the clip, so what we really
1455      want to do is draw directly on the impl, ignoring
1456      client side subwindows. We also use the impl
1457      in the pixmap target case to avoid resetting the
1458      already set clip on the GC. */
1459   if (GDK_IS_WINDOW (drawable))
1460     real_drawable = GDK_WINDOW_OBJECT (drawable)->impl;
1461   else
1462     real_drawable = GDK_PIXMAP_OBJECT (drawable)->impl;
1463
1464   if (gdk_pixbuf_get_has_alpha (pixbuf))
1465     {
1466       GdkVisual *visual = gdk_drawable_get_visual (drawable);
1467       void (*composite_func) (guchar       *src_buf,
1468                               gint          src_rowstride,
1469                               guchar       *dest_buf,
1470                               gint          dest_rowstride,
1471                               GdkByteOrder  dest_byte_order,
1472                               gint          width,
1473                               gint          height) = NULL;
1474
1475       /* First we see if we have a visual-specific composition function that can composite
1476        * the pixbuf data directly onto the image
1477        */
1478       if (visual)
1479         {
1480           gint bits_per_pixel = _gdk_windowing_get_bits_for_depth (gdk_drawable_get_display (drawable),
1481                                                                    visual->depth);
1482           
1483           if (visual->byte_order == (G_BYTE_ORDER == G_BIG_ENDIAN ? GDK_MSB_FIRST : GDK_LSB_FIRST) &&
1484               visual->depth == 16 &&
1485               visual->red_mask   == 0xf800 &&
1486               visual->green_mask == 0x07e0 &&
1487               visual->blue_mask  == 0x001f)
1488             composite_func = composite_565;
1489           else if (visual->depth == 24 && bits_per_pixel == 32 &&
1490                    visual->red_mask   == 0xff0000 &&
1491                    visual->green_mask == 0x00ff00 &&
1492                    visual->blue_mask  == 0x0000ff)
1493             {
1494 #ifdef USE_MEDIALIB
1495               if (_gdk_use_medialib ())
1496                 composite_func = composite_0888_medialib;
1497               else
1498                 composite_func = composite_0888;
1499 #else
1500               composite_func = composite_0888;
1501 #endif
1502             }
1503         }
1504
1505       /* We can't use our composite func if we are required to dither
1506        */
1507       if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24))
1508         {
1509           gint x0, y0;
1510           for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1511             {
1512               gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1513               for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1514                 {
1515                   gint xs0, ys0;
1516                   
1517                   gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1518                   
1519                   GdkImage *image = _gdk_image_get_scratch (gdk_drawable_get_screen (drawable),
1520                                                             width1, height1,
1521                                                             gdk_drawable_get_depth (drawable), &xs0, &ys0);
1522                   
1523                   gdk_drawable_copy_to_image (drawable, image,
1524                                               dest_x + x0, dest_y + y0,
1525                                               xs0, ys0,
1526                                               width1, height1);
1527                   (*composite_func) (gdk_pixbuf_get_pixels (pixbuf) + (src_y + y0) * gdk_pixbuf_get_rowstride (pixbuf) + (src_x + x0) * 4,
1528                                      gdk_pixbuf_get_rowstride (pixbuf),
1529                                      (guchar*)image->mem + ys0 * image->bpl + xs0 * image->bpp,
1530                                      image->bpl,
1531                                      visual->byte_order,
1532                                      width1, height1);
1533                   gdk_draw_image (real_drawable, gc, image,
1534                                   xs0, ys0,
1535                                   dest_x + x0, dest_y + y0,
1536                                   width1, height1);
1537                 }
1538             }
1539           
1540           goto out;
1541         }
1542       else
1543         {
1544           /* No special composition func, convert dest to 24 bit RGB data, composite against
1545            * that, and convert back.
1546            */
1547           composited = gdk_pixbuf_get_from_drawable (NULL,
1548                                                      drawable,
1549                                                      NULL,
1550                                                      dest_x, dest_y,
1551                                                      0, 0,
1552                                                      width, height);
1553           
1554           if (composited)
1555             composite (gdk_pixbuf_get_pixels (pixbuf) + src_y * gdk_pixbuf_get_rowstride (pixbuf) + src_x * 4,
1556                        gdk_pixbuf_get_rowstride (pixbuf),
1557                        gdk_pixbuf_get_pixels (composited),
1558                        gdk_pixbuf_get_rowstride (composited),
1559                        width, height);
1560         }
1561     }
1562
1563   if (composited)
1564     {
1565       src_x = 0;
1566       src_y = 0;
1567       pixbuf = composited;
1568     }
1569   
1570   if (gdk_pixbuf_get_n_channels (pixbuf) == 4)
1571     {
1572       guchar *buf = gdk_pixbuf_get_pixels (pixbuf) + src_y * gdk_pixbuf_get_rowstride (pixbuf) + src_x * 4;
1573
1574       gdk_draw_rgb_32_image_dithalign (real_drawable, gc,
1575                                        dest_x, dest_y,
1576                                        width, height,
1577                                        dither,
1578                                        buf, gdk_pixbuf_get_rowstride (pixbuf),
1579                                        x_dither, y_dither);
1580     }
1581   else                          /* n_channels == 3 */
1582     {
1583       guchar *buf = gdk_pixbuf_get_pixels (pixbuf) + src_y * gdk_pixbuf_get_rowstride (pixbuf) + src_x * 3;
1584
1585       gdk_draw_rgb_image_dithalign (real_drawable, gc,
1586                                     dest_x, dest_y,
1587                                     width, height,
1588                                     dither,
1589                                     buf, gdk_pixbuf_get_rowstride (pixbuf),
1590                                     x_dither, y_dither);
1591     }
1592
1593  out:
1594   if (composited)
1595     g_object_unref (composited);
1596 }
1597
1598 /************************************************************************/
1599
1600 /**
1601  * _gdk_drawable_get_scratch_gc:
1602  * @drawable: A #GdkDrawable
1603  * @graphics_exposures: Whether the returned #GdkGC should generate graphics exposures 
1604  * 
1605  * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has
1606  * the standard values for @drawable, except for the graphics_exposures
1607  * field which is determined by the @graphics_exposures parameter.
1608  *
1609  * The foreground color of the returned #GdkGC is undefined. The #GdkGC
1610  * must not be altered in any way, except to change its foreground color.
1611  * 
1612  * Return value: A #GdkGC suitable for drawing on @drawable
1613  * 
1614  * Since: 2.4
1615  **/
1616 GdkGC *
1617 _gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
1618                               gboolean     graphics_exposures)
1619 {
1620   GdkScreen *screen;
1621   gint depth;
1622
1623   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1624
1625   screen = gdk_drawable_get_screen (drawable);
1626
1627   g_return_val_if_fail (!screen->closed, NULL);
1628
1629   depth = gdk_drawable_get_depth (drawable) - 1;
1630
1631   if (graphics_exposures)
1632     {
1633       if (!screen->exposure_gcs[depth])
1634         {
1635           GdkGCValues values;
1636           GdkGCValuesMask mask;
1637
1638           values.graphics_exposures = TRUE;
1639           mask = GDK_GC_EXPOSURES;  
1640
1641           screen->exposure_gcs[depth] =
1642             gdk_gc_new_with_values (drawable, &values, mask);
1643         }
1644
1645       return screen->exposure_gcs[depth];
1646     }
1647   else
1648     {
1649       if (!screen->normal_gcs[depth])
1650         {
1651           screen->normal_gcs[depth] =
1652             gdk_gc_new (drawable);
1653         }
1654
1655       return screen->normal_gcs[depth];
1656     }
1657 }
1658
1659 /**
1660  * _gdk_drawable_get_subwindow_scratch_gc:
1661  * @drawable: A #GdkDrawable
1662  * 
1663  * Returns a #GdkGC suitable for drawing on @drawable. The #GdkGC has
1664  * the standard values for @drawable, except for the graphics_exposures
1665  * field which is %TRUE and the subwindow mode which is %GDK_INCLUDE_INFERIORS.
1666  *
1667  * The foreground color of the returned #GdkGC is undefined. The #GdkGC
1668  * must not be altered in any way, except to change its foreground color.
1669  * 
1670  * Return value: A #GdkGC suitable for drawing on @drawable
1671  * 
1672  * Since: 2.18
1673  **/
1674 GdkGC *
1675 _gdk_drawable_get_subwindow_scratch_gc (GdkDrawable *drawable)
1676 {
1677   GdkScreen *screen;
1678   gint depth;
1679
1680   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1681
1682   screen = gdk_drawable_get_screen (drawable);
1683
1684   g_return_val_if_fail (!screen->closed, NULL);
1685
1686   depth = gdk_drawable_get_depth (drawable) - 1;
1687
1688   if (!screen->subwindow_gcs[depth])
1689     {
1690       GdkGCValues values;
1691       GdkGCValuesMask mask;
1692       
1693       values.graphics_exposures = TRUE;
1694       values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1695       mask = GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW;  
1696       
1697       screen->subwindow_gcs[depth] =
1698         gdk_gc_new_with_values (drawable, &values, mask);
1699     }
1700   
1701   return screen->subwindow_gcs[depth];
1702 }
1703
1704
1705 /*
1706  * _gdk_drawable_get_source_drawable:
1707  * @drawable: a #GdkDrawable
1708  *
1709  * Returns a drawable for the passed @drawable that is guaranteed to be
1710  * usable to create a pixmap (e.g.: not an offscreen window).
1711  *
1712  * Since: 2.16
1713  */
1714 GdkDrawable *
1715 _gdk_drawable_get_source_drawable (GdkDrawable *drawable)
1716 {
1717   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
1718
1719   if (GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable)
1720     return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable);
1721
1722   return drawable;
1723 }
1724
1725 cairo_surface_t *
1726 _gdk_drawable_create_cairo_surface (GdkDrawable *drawable,
1727                                     int width,
1728                                     int height)
1729 {
1730   return GDK_DRAWABLE_GET_CLASS (drawable)->create_cairo_surface (drawable,
1731                                                                   width, height);
1732 }
1733
1734
1735 #define __GDK_DRAW_C__
1736 #include "gdkaliasdef.c"