]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkimage-win32.c
gdk/win32/gdkimage-win32.c gdk/x11/gdkimage-x11.c Add bounds-checking
[~andy/gtk] / gdk / win32 / gdkimage-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "gdkimage.h"
29 #include "gdkpixmap.h"
30 #include "gdkscreen.h" /* gdk_screen_get_default() */
31 #include "gdkprivate-win32.h"
32
33 static GList *image_list = NULL;
34 static gpointer parent_class = NULL;
35
36 static void gdk_win32_image_destroy (GdkImage      *image);
37 static void gdk_image_init          (GdkImage      *image);
38 static void gdk_image_class_init    (GdkImageClass *klass);
39 static void gdk_image_finalize      (GObject       *object);
40
41 GType
42 gdk_image_get_type (void)
43 {
44   static GType object_type = 0;
45
46   if (!object_type)
47     {
48       static const GTypeInfo object_info =
49       {
50         sizeof (GdkImageClass),
51         (GBaseInitFunc) NULL,
52         (GBaseFinalizeFunc) NULL,
53         (GClassInitFunc) gdk_image_class_init,
54         NULL,           /* class_finalize */
55         NULL,           /* class_data */
56         sizeof (GdkImage),
57         0,              /* n_preallocs */
58         (GInstanceInitFunc) gdk_image_init,
59       };
60       
61       object_type = g_type_register_static (G_TYPE_OBJECT,
62                                             "GdkImage",
63                                             &object_info, 0);
64     }
65   
66   return object_type;
67 }
68
69 static void
70 gdk_image_init (GdkImage *image)
71 {
72   image->windowing_data = NULL;
73 }
74
75 static void
76 gdk_image_class_init (GdkImageClass *klass)
77 {
78   GObjectClass *object_class = G_OBJECT_CLASS (klass);
79
80   parent_class = g_type_class_peek_parent (klass);
81
82   object_class->finalize = gdk_image_finalize;
83 }
84
85 static void
86 gdk_image_finalize (GObject *object)
87 {
88   GdkImage *image = GDK_IMAGE (object);
89
90   gdk_win32_image_destroy (image);
91   
92   G_OBJECT_CLASS (parent_class)->finalize (object);
93 }
94
95 void
96 _gdk_image_exit (void)
97 {
98   GdkImage *image;
99
100   while (image_list)
101     {
102       image = image_list->data;
103       gdk_win32_image_destroy (image);
104     }
105 }
106
107 GdkImage *
108 _gdk_win32_setup_pixmap_image (GdkPixmap *pixmap,
109                                GdkWindow *window,
110                                gint       width,
111                                gint       height,
112                                gint       depth,
113                                guchar    *bits)
114 {
115   GdkImage *image;
116
117   image = g_object_new (gdk_image_get_type (), NULL);
118   image->windowing_data = pixmap;
119   image->type = GDK_IMAGE_SHARED;
120   image->visual = gdk_drawable_get_visual (window);
121   image->byte_order = GDK_LSB_FIRST;
122   image->width = width;
123   image->height = height;
124   image->depth = depth;
125   switch (depth)
126     {
127     case 1:
128     case 4:
129     case 5:
130     case 6:
131     case 7:
132     case 8:
133       image->bpp = 1;
134       break;
135     case 15:
136     case 16:
137       image->bpp = 2;
138       break;
139     case 24:
140       image->bpp = 3;
141       break;
142     case 32:
143       image->bpp = 4;
144       break;
145     default:
146       g_warning ("_gdk_win32_setup_pixmap_image: depth=%d", image->depth);
147       g_assert_not_reached ();
148     }
149   if (depth == 1)
150     image->bpl = ((width - 1)/32 + 1)*4;
151   else if (depth == 4)
152     image->bpl = ((width - 1)/8 + 1)*4;
153   else
154     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
155   image->bits_per_pixel = image->depth;
156   image->mem = bits;
157
158   return image;
159 }
160
161 GdkImage *
162 gdk_image_new_bitmap (GdkVisual *visual,
163                       gpointer   data,
164                       gint       w,
165                       gint       h)
166 {
167   GdkPixmap *pixmap;
168   GdkImage *image;
169   gint data_bpl = (w-1)/8 + 1;
170   gint i;
171
172   pixmap = gdk_pixmap_new (NULL, w, h, 1);
173
174   if (pixmap == NULL)
175     return NULL;
176
177   image = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl)->image;
178
179   GDK_NOTE (IMAGE, g_print ("gdk_image_new_bitmap: %dx%d=%p\n",
180                             w, h, GDK_PIXMAP_HBITMAP (pixmap)));
181   
182   if (data_bpl != image->bpl)
183     {
184       for (i = 0; i < h; i++)
185         memmove ((guchar *) image->mem + i*image->bpl, ((guchar *) data) + i*data_bpl, data_bpl);
186     }
187   else
188     memmove (image->mem, data, data_bpl*h);
189
190   return image;
191 }
192
193 void
194 _gdk_windowing_image_init (void)
195 {
196   /* Nothing needed AFAIK */
197 }
198
199 GdkImage*
200 _gdk_image_new_for_depth (GdkScreen    *screen,
201                           GdkImageType  type,
202                           GdkVisual    *visual,
203                           gint          width,
204                           gint          height,
205                           gint          depth)
206 {
207   GdkPixmap *pixmap;
208
209   g_return_val_if_fail (!visual || GDK_IS_VISUAL (visual), NULL);
210   g_return_val_if_fail (visual || depth != -1, NULL);
211   g_return_val_if_fail (screen == gdk_screen_get_default (), NULL);
212  
213   if (visual)
214     depth = visual->depth;
215
216   pixmap = gdk_pixmap_new (NULL, width, height, depth);
217
218   if (pixmap == NULL)
219     return NULL;
220
221   GDK_NOTE (IMAGE, g_print ("_gdk_image_new_for_depth: %dx%dx%d=%p\n",
222                             width, height, depth, GDK_PIXMAP_HBITMAP (pixmap)));
223   
224   return GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl)->image;
225 }
226
227 GdkImage*
228 _gdk_win32_copy_to_image (GdkDrawable    *drawable,
229                           GdkImage       *image,
230                           gint            src_x,
231                           gint            src_y,
232                           gint            dest_x,
233                           gint            dest_y,
234                           gint            width,
235                           gint            height)
236 {
237   GdkGC *gc;
238   GdkScreen *screen = gdk_drawable_get_screen (drawable);
239   
240   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable), NULL);
241   g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL);
242
243   GDK_NOTE (IMAGE, g_print ("_gdk_win32_copy_to_image: %p\n",
244                             GDK_DRAWABLE_HANDLE (drawable)));
245
246   if (!image)
247     image = _gdk_image_new_for_depth (screen, GDK_IMAGE_FASTEST, NULL, width, height,
248                                       gdk_drawable_get_depth (drawable));
249
250   gc = gdk_gc_new ((GdkDrawable *) image->windowing_data);
251   _gdk_win32_blit
252     (FALSE,
253      GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (image->windowing_data)->impl),
254      gc, drawable, src_x, src_y, dest_x, dest_y, width, height);
255   gdk_gc_unref (gc);
256
257   return image;
258 }
259
260 guint32
261 gdk_image_get_pixel (GdkImage *image,
262                      gint      x,
263                      gint      y)
264 {
265   guchar *pixelp;
266
267   g_return_val_if_fail (image != NULL, 0);
268   g_return_val_if_fail (x < 0 || x >= image->width, 0);
269   g_return_val_if_fail (y < 0 || y >= image->height, 0);
270
271   if (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
272       return 0;
273
274   if (image->depth == 1)
275     return (((guchar *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
276
277   if (image->depth == 4)
278     {
279       pixelp = (guchar *) image->mem + y * image->bpl + (x >> 1);
280       if (x&1)
281         return (*pixelp) & 0x0F;
282
283       return (*pixelp) >> 4;
284     }
285     
286   pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
287       
288   switch (image->bpp)
289     {
290     case 1:
291       return *pixelp;
292       
293       /* Windows is always LSB, no need to check image->byte_order. */
294     case 2:
295       return pixelp[0] | (pixelp[1] << 8);
296       
297     case 3:
298       return pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
299
300     case 4:
301       return pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
302     }
303   g_assert_not_reached ();
304   return 0;
305 }
306
307 void
308 gdk_image_put_pixel (GdkImage *image,
309                      gint       x,
310                      gint       y,
311                      guint32    pixel)
312 {
313   guchar *pixelp;
314
315   g_return_if_fail (image != NULL);
316   g_return_if_fail (x < 0 || x >= image->width);
317   g_return_if_fail (y < 0 || y >= image->height);
318
319   if  (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
320     return;
321
322   GdiFlush ();
323   if (image->depth == 1)
324     if (pixel & 1)
325       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
326     else
327       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
328   else if (image->depth == 4)
329     {
330       pixelp = (guchar *) image->mem + y * image->bpl + (x >> 1);
331
332       if (x&1)
333         {
334           *pixelp &= 0xF0;
335           *pixelp |= (pixel & 0x0F);
336         }
337       else
338         {
339           *pixelp &= 0x0F;
340           *pixelp |= (pixel << 4);
341         }
342     }
343   else
344     {
345       pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
346       
347       /* Windows is always LSB, no need to check image->byte_order. */
348       switch (image->bpp)
349         {
350         case 4:
351           pixelp[3] = 0;
352         case 3:
353           pixelp[2] = ((pixel >> 16) & 0xFF);
354         case 2:
355           pixelp[1] = ((pixel >> 8) & 0xFF);
356         case 1:
357           pixelp[0] = (pixel & 0xFF);
358         }
359     }
360 }
361
362 static void
363 gdk_win32_image_destroy (GdkImage *image)
364 {
365   GdkPixmap *pixmap;
366
367   g_return_if_fail (GDK_IS_IMAGE (image));
368
369   pixmap = image->windowing_data;
370
371   if (pixmap == NULL)           /* This means that _gdk_image_exit()
372                                  * destroyed the image already, and
373                                  * now we're called a second time from
374                                  * _finalize()
375                                  */
376     return;
377   
378   GDK_NOTE (IMAGE, g_print ("gdk_win32_image_destroy: %p\n",
379                             GDK_PIXMAP_HBITMAP (pixmap)));
380
381   gdk_pixmap_unref (pixmap);
382   image->windowing_data = NULL;
383 }
384
385 gint
386 _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
387                                    gint        depth)
388 {
389   g_return_val_if_fail (display == gdk_display_get_default (), 0);
390
391   switch (depth)
392     {
393     case 1:
394       return 1;
395
396     case 2:
397     case 3:
398     case 4:
399       return 4;
400
401     case 5:
402     case 6:
403     case 7:
404     case 8:
405       return 8;
406
407     case 15:
408     case 16:
409       return 16;
410
411     case 24:
412       return 24;
413
414     case 32:
415       return 32;
416     }
417   g_assert_not_reached ();
418   return 0;
419 }