~bratsche/ubuntu/maverick/gtk+2.0/menu-activation-fix

« back to all changes in this revision

Viewing changes to gdk-pixbuf/gdk-pixdata.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-07-22 21:41:30 UTC
  • mfrom: (1.11.7 upstream) (72.1.16 experimental)
  • Revision ID: james.westby@ubuntu.com-20100722214130-5uzyvpb9g4m0ts2c
Tags: 2.21.5-1ubuntu1
* Merge with Debian experimental, Ubuntu changes:
* debian/control.in:
  - Add introspection build-depends
  - Add Vcs-Bzr link
  - Add gir1.0-gtk-2.0 package
  - libgtk2.0-dev replaces gir-repository-dev
  - Conflict with appmenu-gtk (<< 0.1.3) to prevent menu proxy breakage
* debian/rules:
  - Build with --enable-introspection
  - Add gir1.0-gtk-2.0 package to BINARY_ARCH_PKGS
  - Add dh_girepository call
  - Disable devhelp files
* debian/dh_gtkmodules.in:
  - Remove obsolete script content
* debian/libgtk2.0-0.symbols:
  - Add Ubuntu specific symbols
* debian/libgtk2.0-dev.install.in:
  - Add gir files
* debian/libgtk2.0-doc.install.in
  - Disable devhelp files
* debian/gir1.0-gtk-2.0.install.in
  - Introspection package
* debian/patches/043_menu_proxy.patch
  - Add GtkMenuProxy support for remoting menus.
* debian/patches/062_dnd_menubar.patch:
  - Allow click on menubars for dnd
* debian/patches/063_treeview_almost_fixed.patch:
  - Add an ubuntu-almost-fixed-height-mode property, (required for
    software-center)
* debian/patches/071_no_offscreen_widgets_grabbing.patch:
  - Don't let offscreen widgets do grabbing
* debian/patches/072_indicator_menu_update.patch:
  - change by Cody Russell to send an update event on menu changes,
    should make the bluetooth indicator refresh correctly
* debian/patches/091_bugzilla_tooltip_refresh.patch:
  - Upstream bugzilla change to have better looking tooltips the gtk theme
    need to set "new-tooltip-style" to use those
* debian/watch:
  - Watch for unstable versions

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
2
 
 * Copyright (C) 1999, 2001 Tim Janik
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
 
#include "config.h"
20
 
 
21
 
#include "gdk-pixbuf-private.h"
22
 
#include "gdk-pixdata.h"
23
 
#include "gdk-pixbuf-alias.h"
24
 
#include <string.h>
25
 
 
26
 
#define APPEND g_string_append_printf
27
 
 
28
 
/* --- functions --- */
29
 
static guint
30
 
pixdata_get_length (const GdkPixdata *pixdata)
31
 
{
32
 
  guint bpp, length;
33
 
 
34
 
  if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
35
 
    bpp = 3;
36
 
  else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
37
 
    bpp = 4;
38
 
  else
39
 
    return 0;   /* invalid format */
40
 
  switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
41
 
    {
42
 
      guint8 *rle_buffer;
43
 
      guint max_length;
44
 
    case GDK_PIXDATA_ENCODING_RAW:
45
 
      length = pixdata->rowstride * pixdata->height;
46
 
      break;
47
 
    case GDK_PIXDATA_ENCODING_RLE:
48
 
      /* need an RLE walk to determine size */
49
 
      max_length = pixdata->rowstride * pixdata->height;
50
 
      rle_buffer = pixdata->pixel_data;
51
 
      length = 0;
52
 
      while (length < max_length)
53
 
        {
54
 
          guint chunk_length = *(rle_buffer++);
55
 
 
56
 
          if (chunk_length & 128)
57
 
            {
58
 
              chunk_length = chunk_length - 128;
59
 
              if (!chunk_length)        /* RLE data corrupted */
60
 
                return 0;
61
 
              length += chunk_length * bpp;
62
 
              rle_buffer += bpp;
63
 
            }
64
 
          else
65
 
            {
66
 
              if (!chunk_length)        /* RLE data corrupted */
67
 
                return 0;
68
 
              chunk_length *= bpp;
69
 
              length += chunk_length;
70
 
              rle_buffer += chunk_length;
71
 
            }
72
 
        }
73
 
      length = rle_buffer - pixdata->pixel_data;
74
 
      break;
75
 
    default:
76
 
      length = 0;
77
 
      break;
78
 
    }
79
 
  return length;
80
 
}
81
 
 
82
 
/**
83
 
 * gdk_pixdata_serialize:
84
 
 * @pixdata: a valid #GdkPixdata structure to serialize.
85
 
 * @stream_length_p: location to store the resulting stream length in.
86
 
 *
87
 
 * Serializes a #GdkPixdata structure into a byte stream.
88
 
 * The byte stream consists of a straightforward writeout of the
89
 
 * #GdkPixdata fields in network byte order, plus the @pixel_data
90
 
 * bytes the structure points to.
91
 
 *
92
 
 * Return value: A newly-allocated string containing the serialized
93
 
 * #GdkPixdata structure.
94
 
 **/
95
 
guint8* /* free result */
96
 
gdk_pixdata_serialize (const GdkPixdata *pixdata,
97
 
                       guint            *stream_length_p)
98
 
{
99
 
  guint8 *stream, *s;
100
 
  guint32 *istream;
101
 
  guint length;
102
 
 
103
 
  /* check args passing */
104
 
  g_return_val_if_fail (pixdata != NULL, NULL);
105
 
  g_return_val_if_fail (stream_length_p != NULL, NULL);
106
 
  /* check pixdata contents */
107
 
  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
108
 
  g_return_val_if_fail (pixdata->width > 0, NULL);
109
 
  g_return_val_if_fail (pixdata->height > 0, NULL);
110
 
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
111
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
112
 
                        (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
113
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
114
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
115
 
                        (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
116
 
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
117
 
 
118
 
  length = pixdata_get_length (pixdata);
119
 
 
120
 
  /* check length field */
121
 
  g_return_val_if_fail (length != 0, NULL);
122
 
  
123
 
  stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
124
 
  istream = (guint32*) stream;
125
 
 
126
 
  /* store header */
127
 
  *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
128
 
  *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
129
 
  *istream++ = g_htonl (pixdata->pixdata_type);
130
 
  *istream++ = g_htonl (pixdata->rowstride);
131
 
  *istream++ = g_htonl (pixdata->width);
132
 
  *istream++ = g_htonl (pixdata->height);
133
 
 
134
 
  /* copy pixel data */
135
 
  s = (guint8*) istream;
136
 
  memcpy (s, pixdata->pixel_data, length);
137
 
  s += length;
138
 
 
139
 
  *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
140
 
  g_assert (s - stream == *stream_length_p);    /* paranoid */
141
 
 
142
 
  return stream;
143
 
}
144
 
 
145
 
#define return_header_corrupt(error)    { \
146
 
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
147
 
                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image header corrupt")); \
148
 
  return FALSE; \
149
 
}
150
 
#define return_invalid_format(error)    { \
151
 
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
152
 
                       GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image format unknown")); \
153
 
  return FALSE; \
154
 
}
155
 
#define return_pixel_corrupt(error)     { \
156
 
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
157
 
                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); \
158
 
  return FALSE; \
159
 
}
160
 
 
161
 
static inline const guint8 *
162
 
get_uint32 (const guint8 *stream, guint *result)
163
 
{
164
 
  *result = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
165
 
  return stream + 4;
166
 
}
167
 
 
168
 
/**
169
 
 * gdk_pixdata_deserialize:
170
 
 * @pixdata: a #GdkPixdata structure to be filled in.
171
 
 * @stream_length: length of the stream used for deserialization.
172
 
 * @stream: stream of bytes containing a serialized #GdkPixdata structure.
173
 
 * @error: #GError location to indicate failures (maybe %NULL to ignore errors).
174
 
 *
175
 
 * Deserializes (reconstruct) a #GdkPixdata structure from a byte stream.
176
 
 * The byte stream consists of a straightforward writeout of the
177
 
 * #GdkPixdata fields in network byte order, plus the @pixel_data
178
 
 * bytes the structure points to.
179
 
 * The @pixdata contents are reconstructed byte by byte and are checked
180
 
 * for validity. This function may fail with %GDK_PIXBUF_CORRUPT_IMAGE
181
 
 * or %GDK_PIXBUF_ERROR_UNKNOWN_TYPE.
182
 
 *
183
 
 * Return value: Upon successful deserialization %TRUE is returned,
184
 
 * %FALSE otherwise.
185
 
 **/
186
 
gboolean
187
 
gdk_pixdata_deserialize (GdkPixdata   *pixdata,
188
 
                         guint         stream_length,
189
 
                         const guint8 *stream,
190
 
                         GError      **error)
191
 
{
192
 
  guint color_type, sample_width, encoding;
193
 
 
194
 
  g_return_val_if_fail (pixdata != NULL, FALSE);
195
 
  if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
196
 
    return_header_corrupt (error);
197
 
  g_return_val_if_fail (stream != NULL, FALSE);
198
 
 
199
 
 
200
 
  /* deserialize header */
201
 
  stream = get_uint32 (stream, &pixdata->magic);
202
 
  stream = get_uint32 (stream, (guint32 *)&pixdata->length);
203
 
  if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
204
 
    return_header_corrupt (error);
205
 
  stream = get_uint32 (stream, &pixdata->pixdata_type);
206
 
  stream = get_uint32 (stream, &pixdata->rowstride);
207
 
  stream = get_uint32 (stream, &pixdata->width);
208
 
  stream = get_uint32 (stream, &pixdata->height);
209
 
  if (pixdata->width < 1 || pixdata->height < 1 ||
210
 
      pixdata->rowstride < pixdata->width)
211
 
    return_header_corrupt (error);
212
 
  color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
213
 
  sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
214
 
  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
215
 
  if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
216
 
       color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
217
 
      sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
218
 
      (encoding != GDK_PIXDATA_ENCODING_RAW &&
219
 
       encoding != GDK_PIXDATA_ENCODING_RLE))
220
 
    return_invalid_format (error);
221
 
 
222
 
  /* deserialize pixel data */
223
 
  if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
224
 
    return_pixel_corrupt (error);
225
 
  pixdata->pixel_data = (guint8 *)stream;
226
 
 
227
 
  return TRUE;
228
 
}
229
 
 
230
 
static gboolean
231
 
diff2_rgb (guint8 *ip)
232
 
{
233
 
  return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
234
 
}
235
 
 
236
 
static gboolean
237
 
diff2_rgba (guint8 *ip)
238
 
{
239
 
  return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
240
 
}
241
 
 
242
 
static guint8*                  /* dest buffer bound */
243
 
rl_encode_rgbx (guint8 *bp,     /* dest buffer */
244
 
                guint8 *ip,     /* image pointer */
245
 
                guint8 *limit,  /* image upper bound */
246
 
                guint   n_ch)
247
 
{
248
 
  gboolean (*diff2_pix) (guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
249
 
  guint8 *ilimit = limit - n_ch;
250
 
 
251
 
  while (ip < limit)
252
 
    {
253
 
      g_assert (ip < ilimit); /* paranoid */
254
 
 
255
 
      if (diff2_pix (ip))
256
 
        {
257
 
          guint8 *s_ip = ip;
258
 
          guint l = 1;
259
 
 
260
 
          ip += n_ch;
261
 
          while (l < 127 && ip < ilimit && diff2_pix (ip))
262
 
            { ip += n_ch; l += 1; }
263
 
          if (ip == ilimit && l < 127)
264
 
            { ip += n_ch; l += 1; }
265
 
          *(bp++) = l;
266
 
          memcpy (bp, s_ip, l * n_ch);
267
 
          bp += l * n_ch;
268
 
        }
269
 
      else
270
 
        {
271
 
          guint l = 2;
272
 
 
273
 
          ip += n_ch;
274
 
          while (l < 127 && ip < ilimit && !diff2_pix (ip))
275
 
            { ip += n_ch; l += 1; }
276
 
          *(bp++) = l | 128;
277
 
          memcpy (bp, ip, n_ch);
278
 
          ip += n_ch;
279
 
          bp += n_ch;
280
 
        }
281
 
      if (ip == ilimit)
282
 
        {
283
 
          *(bp++) = 1;
284
 
          memcpy (bp, ip, n_ch);
285
 
          ip += n_ch;
286
 
          bp += n_ch;
287
 
        }
288
 
    }
289
 
 
290
 
  return bp;
291
 
}
292
 
 
293
 
/* Used as the destroy notification function for gdk_pixbuf_new() */
294
 
static void
295
 
free_buffer (guchar *pixels, gpointer data)
296
 
{
297
 
        g_free (pixels);
298
 
}
299
 
 
300
 
/**
301
 
 * gdk_pixdata_from_pixbuf:
302
 
 * @pixdata: a #GdkPixdata to fill.
303
 
 * @pixbuf: the data to fill @pixdata with.
304
 
 * @use_rle: whether to use run-length encoding for the pixel data.
305
 
 *
306
 
 * Converts a #GdkPixbuf to a #GdkPixdata. If @use_rle is %TRUE, the
307
 
 * pixel data is run-length encoded into newly-allocated memory and a 
308
 
 * pointer to that memory is returned. 
309
 
 *
310
 
 * Returns: If @ure_rle is %TRUE, a pointer to the newly-allocated memory 
311
 
 *   for the run-length encoded pixel data, otherwise %NULL.
312
 
 **/
313
 
gpointer
314
 
gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
315
 
                         const GdkPixbuf *pixbuf,
316
 
                         gboolean         use_rle)
317
 
{
318
 
  gpointer free_me = NULL;
319
 
  guint height, rowstride, encoding, bpp, length;
320
 
  guint8 *img_buffer;
321
 
 
322
 
  g_return_val_if_fail (pixdata != NULL, NULL);
323
 
  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
324
 
  g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
325
 
  g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
326
 
                        (pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
327
 
  g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
328
 
 
329
 
  height = pixbuf->height;
330
 
  rowstride = pixbuf->rowstride;
331
 
  bpp = pixbuf->has_alpha ? 4 : 3;
332
 
  encoding = use_rle && ((rowstride / bpp | height) > 1) ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
333
 
 
334
 
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
335
 
    {
336
 
      guint pad, n_bytes = rowstride * height;
337
 
      guint8 *img_buffer_end, *data;
338
 
      GdkPixbuf *buf = NULL;
339
 
 
340
 
      if (n_bytes % bpp != 0) 
341
 
        {
342
 
          rowstride = pixbuf->width * bpp;
343
 
          n_bytes = rowstride * height;
344
 
          data = g_malloc (n_bytes);
345
 
          buf = gdk_pixbuf_new_from_data (data,
346
 
                                          GDK_COLORSPACE_RGB,
347
 
                                          pixbuf->has_alpha, 8,
348
 
                                          pixbuf->width,
349
 
                                          pixbuf->height,
350
 
                                          rowstride,
351
 
                                          free_buffer, NULL);
352
 
          gdk_pixbuf_copy_area (pixbuf, 0, 0, pixbuf->width, pixbuf->height,
353
 
                                buf, 0, 0);
354
 
        }
355
 
      else
356
 
        buf = (GdkPixbuf *)pixbuf;
357
 
      pad = rowstride;
358
 
      pad = MAX (pad, 130 + n_bytes / 127);
359
 
      data = g_new (guint8, pad + n_bytes);
360
 
      free_me = data;
361
 
      img_buffer = data;
362
 
      img_buffer_end = rl_encode_rgbx (img_buffer,
363
 
                                       buf->pixels, buf->pixels + n_bytes,
364
 
                                       bpp);
365
 
      length = img_buffer_end - img_buffer;
366
 
      if (buf != pixbuf)
367
 
        g_object_unref (buf);
368
 
    }
369
 
  else
370
 
    {
371
 
      img_buffer = pixbuf->pixels;
372
 
      length = rowstride * height;
373
 
    }
374
 
 
375
 
  pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
376
 
  pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
377
 
  pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
378
 
  pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
379
 
  pixdata->pixdata_type |= encoding;
380
 
  pixdata->rowstride = rowstride;
381
 
  pixdata->width = pixbuf->width;
382
 
  pixdata->height = height;
383
 
  pixdata->pixel_data = img_buffer;
384
 
 
385
 
  return free_me;
386
 
}
387
 
 
388
 
/**
389
 
 * gdk_pixbuf_from_pixdata:
390
 
 * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
391
 
 * @copy_pixels: whether to copy raw pixel data; run-length encoded
392
 
 *     pixel data is always copied.
393
 
 * @error: location to store possible errors.
394
 
 * 
395
 
 * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or
396
 
 * if the pixel data is run-length-encoded, the pixel data is copied into
397
 
 * newly-allocated memory; otherwise it is reused.
398
 
 *
399
 
 * Returns: a new #GdkPixbuf.
400
 
 **/
401
 
GdkPixbuf*
402
 
gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
403
 
                         gboolean          copy_pixels,
404
 
                         GError          **error)
405
 
{
406
 
  guint encoding, bpp;
407
 
  guint8 *data = NULL;
408
 
 
409
 
  g_return_val_if_fail (pixdata != NULL, NULL);
410
 
  g_return_val_if_fail (pixdata->width > 0, NULL);
411
 
  g_return_val_if_fail (pixdata->height > 0, NULL);
412
 
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
413
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
414
 
                        (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
415
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
416
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
417
 
                        (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
418
 
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
419
 
 
420
 
  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
421
 
  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
422
 
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
423
 
    copy_pixels = TRUE;
424
 
  if (copy_pixels)
425
 
    {
426
 
      data = g_try_malloc (pixdata->rowstride * pixdata->height);
427
 
      if (!data)
428
 
        {
429
 
          g_set_error (error, GDK_PIXBUF_ERROR,
430
 
                       GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
431
 
                       g_dngettext(GETTEXT_PACKAGE,
432
 
                                   "failed to allocate image buffer of %u byte",
433
 
                                   "failed to allocate image buffer of %u bytes",
434
 
                                   pixdata->rowstride * pixdata->height),
435
 
                       pixdata->rowstride * pixdata->height);
436
 
          return NULL;
437
 
        }
438
 
    }
439
 
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
440
 
    {
441
 
      const guint8 *rle_buffer = pixdata->pixel_data;
442
 
      guint8 *image_buffer = data;
443
 
      guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
444
 
      gboolean check_overrun = FALSE;
445
 
 
446
 
      while (image_buffer < image_limit)
447
 
        {
448
 
          guint length = *(rle_buffer++);
449
 
 
450
 
          if (length & 128)
451
 
            {
452
 
              length = length - 128;
453
 
              check_overrun = image_buffer + length * bpp > image_limit;
454
 
              if (check_overrun)
455
 
                length = (image_limit - image_buffer) / bpp;
456
 
              if (bpp < 4)      /* RGB */
457
 
                do
458
 
                  {
459
 
                    memcpy (image_buffer, rle_buffer, 3);
460
 
                    image_buffer += 3;
461
 
                  }
462
 
                while (--length);
463
 
              else              /* RGBA */
464
 
                do
465
 
                  {
466
 
                    memcpy (image_buffer, rle_buffer, 4);
467
 
                    image_buffer += 4;
468
 
                  }
469
 
                while (--length);
470
 
              rle_buffer += bpp;
471
 
            }
472
 
          else
473
 
            {
474
 
              length *= bpp;
475
 
              check_overrun = image_buffer + length > image_limit;
476
 
              if (check_overrun)
477
 
                length = image_limit - image_buffer;
478
 
              memcpy (image_buffer, rle_buffer, length);
479
 
              image_buffer += length;
480
 
              rle_buffer += length;
481
 
            }
482
 
        }
483
 
      if (check_overrun)
484
 
        {
485
 
          g_free (data);
486
 
          g_set_error_literal (error, GDK_PIXBUF_ERROR,
487
 
                               GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
488
 
                               _("Image pixel data corrupt"));
489
 
          return NULL;
490
 
        }
491
 
    }
492
 
  else if (copy_pixels)
493
 
    memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
494
 
  else
495
 
    data = pixdata->pixel_data;
496
 
 
497
 
  return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
498
 
                                   (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
499
 
                                   8, pixdata->width, pixdata->height, pixdata->rowstride,
500
 
                                   copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
501
 
}
502
 
 
503
 
typedef struct {
504
 
  /* config */
505
 
  gboolean     dump_stream;
506
 
  gboolean     dump_struct;
507
 
  gboolean     dump_macros;
508
 
  gboolean     dump_gtypes;
509
 
  gboolean     dump_rle_decoder;
510
 
  const gchar *static_prefix;
511
 
  const gchar *const_prefix;
512
 
  /* runtime */
513
 
  GString *gstring;
514
 
  guint    pos;
515
 
  gboolean pad;
516
 
} CSourceData;
517
 
 
518
 
static inline void
519
 
save_uchar (CSourceData *cdata,
520
 
            guint8       d)
521
 
{
522
 
  GString *gstring = cdata->gstring;
523
 
 
524
 
  if (cdata->pos > 70)
525
 
    {
526
 
      if (cdata->dump_struct || cdata->dump_stream)
527
 
        {
528
 
          g_string_append (gstring, "\"\n  \"");
529
 
          cdata->pos = 3;
530
 
          cdata->pad = FALSE;
531
 
        }
532
 
      if (cdata->dump_macros)
533
 
        {
534
 
          g_string_append (gstring, "\" \\\n  \"");
535
 
          cdata->pos = 3;
536
 
          cdata->pad = FALSE;
537
 
        }
538
 
    }
539
 
  if (d < 33 || d > 126 || d == '?')
540
 
    {
541
 
      APPEND (gstring, "\\%o", d);
542
 
      cdata->pos += 1 + 1 + (d > 7) + (d > 63);
543
 
      cdata->pad = d < 64;
544
 
      return;
545
 
    }
546
 
  if (d == '\\')
547
 
    {
548
 
      g_string_append (gstring, "\\\\");
549
 
      cdata->pos += 2;
550
 
    }
551
 
  else if (d == '"')
552
 
    {
553
 
      g_string_append (gstring, "\\\"");
554
 
      cdata->pos += 2;
555
 
    }
556
 
  else if (cdata->pad && d >= '0' && d <= '9')
557
 
    {
558
 
      g_string_append (gstring, "\"\"");
559
 
      g_string_append_c (gstring, d);
560
 
      cdata->pos += 3;
561
 
    }
562
 
  else
563
 
    {
564
 
      g_string_append_c (gstring, d);
565
 
      cdata->pos += 1;
566
 
    }
567
 
  cdata->pad = FALSE;
568
 
  return;
569
 
}
570
 
 
571
 
static inline void
572
 
save_rle_decoder (GString     *gstring,
573
 
                  const gchar *macro_name,
574
 
                  const gchar *s_uint,
575
 
                  const gchar *s_uint_8,
576
 
                  guint        n_ch)
577
 
{
578
 
  APPEND (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
579
 
          macro_name);
580
 
  APPEND (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
581
 
  APPEND (gstring, "  __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
582
 
  
583
 
  APPEND (gstring, "  __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
584
 
  
585
 
  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
586
 
  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
587
 
  APPEND (gstring, "        do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
588
 
  APPEND (gstring, "      } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
589
 
  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
590
 
  
591
 
  APPEND (gstring, "  } else { /* RGB */ \\\n");
592
 
  
593
 
  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
594
 
  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
595
 
  APPEND (gstring, "        do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
596
 
  APPEND (gstring, "      } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
597
 
  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
598
 
  
599
 
  APPEND (gstring, "  } } while (0)\n");
600
 
}
601
 
 
602
 
/**
603
 
 * gdk_pixdata_to_csource:
604
 
 * @pixdata: a #GdkPixdata to convert to C source.
605
 
 * @name: used for naming generated data structures or macros.
606
 
 * @dump_type: a #GdkPixdataDumpType determining the kind of C
607
 
 *   source to be generated.
608
 
 *
609
 
 * Generates C source code suitable for compiling images directly 
610
 
 * into programs. 
611
 
 *
612
 
 * GTK+ ships with a program called <command>gdk-pixbuf-csource</command> 
613
 
 * which offers a command line interface to this function.
614
 
 *
615
 
 * Returns: a newly-allocated string containing the C source form
616
 
 *   of @pixdata.
617
 
 **/
618
 
GString*
619
 
gdk_pixdata_to_csource (GdkPixdata        *pixdata,
620
 
                        const gchar       *name,
621
 
                        GdkPixdataDumpType dump_type)
622
 
{
623
 
  CSourceData cdata = { 0, };
624
 
  gchar *s_uint_8;
625
 
  guint bpp, width, height, rowstride;
626
 
  gboolean rle_encoded;
627
 
  gchar *macro_name;
628
 
  guint8 *img_buffer, *img_buffer_end, *stream = NULL;
629
 
  guint stream_length;
630
 
  GString *gstring;
631
 
  
632
 
  /* check args passing */
633
 
  g_return_val_if_fail (pixdata != NULL, NULL);
634
 
  g_return_val_if_fail (name != NULL, NULL);
635
 
  /* check pixdata contents */
636
 
  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
637
 
  g_return_val_if_fail (pixdata->width > 0, NULL);
638
 
  g_return_val_if_fail (pixdata->height > 0, NULL);
639
 
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
640
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
641
 
                        (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
642
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
643
 
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
644
 
                        (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
645
 
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
646
 
 
647
 
  img_buffer = pixdata->pixel_data;
648
 
  if (pixdata->length < 1)
649
 
    img_buffer_end = img_buffer + pixdata_get_length (pixdata);
650
 
  else
651
 
    img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
652
 
  g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
653
 
 
654
 
  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
655
 
  width = pixdata->width;
656
 
  height = pixdata->height;
657
 
  rowstride = pixdata->rowstride;
658
 
  rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
659
 
  macro_name = g_ascii_strup (name, -1);
660
 
 
661
 
  cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
662
 
  cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
663
 
  cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
664
 
  g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
665
 
 
666
 
  cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
667
 
  cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
668
 
  cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
669
 
  cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
670
 
  gstring = g_string_new (NULL);
671
 
  cdata.gstring = gstring;
672
 
 
673
 
  if (!cdata.dump_macros && cdata.dump_gtypes)
674
 
    s_uint_8 =  "guint8 ";
675
 
  else if (!cdata.dump_macros)
676
 
    s_uint_8 =  "unsigned char";
677
 
  else if (cdata.dump_macros && cdata.dump_gtypes)
678
 
    s_uint_8 =  "guint8";
679
 
  else /* cdata.dump_macros && !cdata.dump_gtypes */
680
 
    s_uint_8 =  "unsigned char";
681
 
 
682
 
  /* initial comment
683
 
   */
684
 
  APPEND (gstring,
685
 
          "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
686
 
          bpp > 3 ? "RGBA" : "RGB",
687
 
          rle_encoded ? "1-byte-run-length-encoded " : "");
688
 
  
689
 
  /* dump RLE decoder for structures
690
 
   */
691
 
  if (cdata.dump_rle_decoder && cdata.dump_struct)
692
 
    save_rle_decoder (gstring,
693
 
                      macro_name,
694
 
                      cdata.dump_gtypes ? "guint" : "unsigned int",
695
 
                      cdata.dump_gtypes ? "guint8" : "unsigned char",
696
 
                      bpp);
697
 
 
698
 
  /* format & size blurbs
699
 
   */
700
 
  if (cdata.dump_macros)
701
 
    {
702
 
      APPEND (gstring, "#define %s_ROWSTRIDE (%u)\n",
703
 
              macro_name, rowstride);
704
 
      APPEND (gstring, "#define %s_WIDTH (%u)\n",
705
 
              macro_name, width);
706
 
      APPEND (gstring, "#define %s_HEIGHT (%u)\n",
707
 
              macro_name, height);
708
 
      APPEND (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
709
 
              macro_name, bpp);
710
 
    }
711
 
  if (cdata.dump_struct)
712
 
    {
713
 
      APPEND (gstring, "%s%sGdkPixdata %s = {\n",
714
 
              cdata.static_prefix, cdata.const_prefix, name);
715
 
      APPEND (gstring, "  0x%x, /* Pixbuf magic: 'GdkP' */\n",
716
 
              GDK_PIXBUF_MAGIC_NUMBER);
717
 
      APPEND (gstring, "  %d + %lu, /* header length + pixel_data length */\n",
718
 
              GDK_PIXDATA_HEADER_LENGTH,
719
 
              rle_encoded ? (glong)(img_buffer_end - img_buffer) : (glong)rowstride * height);
720
 
      APPEND (gstring, "  0x%x, /* pixdata_type */\n",
721
 
              pixdata->pixdata_type);
722
 
      APPEND (gstring, "  %u, /* rowstride */\n",
723
 
              rowstride);
724
 
      APPEND (gstring, "  %u, /* width */\n",
725
 
              width);
726
 
      APPEND (gstring, "  %u, /* height */\n",
727
 
              height);
728
 
      APPEND (gstring, "  /* pixel_data: */\n");
729
 
    }
730
 
  if (cdata.dump_stream)
731
 
    {
732
 
      guint pix_length = img_buffer_end - img_buffer;
733
 
      
734
 
      stream = gdk_pixdata_serialize (pixdata, &stream_length);
735
 
      img_buffer = stream;
736
 
      img_buffer_end = stream + stream_length;
737
 
 
738
 
      APPEND (gstring, "#ifdef __SUNPRO_C\n");
739
 
      APPEND (gstring, "#pragma align 4 (%s)\n", name);   
740
 
      APPEND (gstring, "#endif\n");
741
 
 
742
 
      APPEND (gstring, "#ifdef __GNUC__\n");
743
 
      APPEND (gstring, "%s%s%s %s[] __attribute__ ((__aligned__ (4))) = \n",
744
 
              cdata.static_prefix, cdata.const_prefix,
745
 
              cdata.dump_gtypes ? "guint8" : "unsigned char",
746
 
              name);
747
 
      APPEND (gstring, "#else\n");
748
 
      APPEND (gstring, "%s%s%s %s[] = \n",
749
 
              cdata.static_prefix, cdata.const_prefix,
750
 
              cdata.dump_gtypes ? "guint8" : "unsigned char",
751
 
              name);
752
 
      APPEND (gstring, "#endif\n");
753
 
 
754
 
      APPEND (gstring, "{ \"\"\n  /* Pixbuf magic (0x%x) */\n  \"",
755
 
              GDK_PIXBUF_MAGIC_NUMBER);
756
 
      cdata.pos = 3;
757
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
758
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
759
 
      APPEND (gstring, "\"\n  /* length: header (%d) + pixel_data (%u) */\n  \"",
760
 
              GDK_PIXDATA_HEADER_LENGTH,
761
 
              rle_encoded ? pix_length : rowstride * height);
762
 
      cdata.pos = 3;
763
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
764
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
765
 
      APPEND (gstring, "\"\n  /* pixdata_type (0x%x) */\n  \"",
766
 
              pixdata->pixdata_type);
767
 
      cdata.pos = 3;
768
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
769
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
770
 
      APPEND (gstring, "\"\n  /* rowstride (%u) */\n  \"",
771
 
              rowstride);
772
 
      cdata.pos = 3;
773
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
774
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
775
 
      APPEND (gstring, "\"\n  /* width (%u) */\n  \"", width);
776
 
      cdata.pos = 3;
777
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
778
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
779
 
      APPEND (gstring, "\"\n  /* height (%u) */\n  \"", height);
780
 
      cdata.pos = 3;
781
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
782
 
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
783
 
      APPEND (gstring, "\"\n  /* pixel_data: */\n");
784
 
    }
785
 
 
786
 
  /* pixel_data intro
787
 
   */
788
 
  if (cdata.dump_macros)
789
 
    {
790
 
      APPEND (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
791
 
              macro_name,
792
 
              rle_encoded ? "RLE_" : "",
793
 
              s_uint_8);
794
 
      APPEND (gstring, "  \"");
795
 
      cdata.pos = 2;
796
 
    }
797
 
  if (cdata.dump_struct)
798
 
    {
799
 
      APPEND (gstring, "  \"");
800
 
      cdata.pos = 3;
801
 
    }
802
 
  if (cdata.dump_stream)
803
 
    {
804
 
      APPEND (gstring, "  \"");
805
 
      cdata.pos = 3;
806
 
    }
807
 
    
808
 
  /* pixel_data
809
 
   */
810
 
  do
811
 
    save_uchar (&cdata, *img_buffer++);
812
 
  while (img_buffer < img_buffer_end);
813
 
 
814
 
  /* pixel_data trailer
815
 
   */
816
 
  if (cdata.dump_macros)
817
 
    APPEND (gstring, "\")\n\n");
818
 
  if (cdata.dump_struct)
819
 
    APPEND (gstring, "\",\n};\n\n");
820
 
  if (cdata.dump_stream)
821
 
    APPEND (gstring, "\"};\n\n");
822
 
 
823
 
  /* dump RLE decoder for macros
824
 
   */
825
 
  if (cdata.dump_rle_decoder && cdata.dump_macros)
826
 
    save_rle_decoder (gstring,
827
 
                      macro_name,
828
 
                      cdata.dump_gtypes ? "guint" : "unsigned int",
829
 
                      cdata.dump_gtypes ? "guint8" : "unsigned char",
830
 
                      bpp);
831
 
 
832
 
  /* cleanup
833
 
   */
834
 
  g_free (stream);
835
 
  g_free (macro_name);
836
 
    
837
 
  return gstring;
838
 
}
839
 
 
840
 
/**
841
 
 * gdk_pixbuf_new_from_inline:
842
 
 * @data_length: Length in bytes of the @data argument or -1 to 
843
 
 *    disable length checks
844
 
 * @data: Byte data containing a serialized #GdkPixdata structure
845
 
 * @copy_pixels: Whether to copy the pixel data, or use direct pointers
846
 
 *               @data for the resulting pixbuf
847
 
 * @error: #GError return location, may be %NULL to ignore errors
848
 
 *
849
 
 * Create a #GdkPixbuf from a flat representation that is suitable for
850
 
 * storing as inline data in a program. This is useful if you want to
851
 
 * ship a program with images, but don't want to depend on any
852
 
 * external files.
853
 
 *
854
 
 * GTK+ ships with a program called <command>gdk-pixbuf-csource</command> 
855
 
 * which allows for conversion of #GdkPixbufs into such a inline representation.
856
 
 * In almost all cases, you should pass the <option>--raw</option> flag to
857
 
 * <command>gdk-pixbuf-csource</command>. A sample invocation would be:
858
 
 *
859
 
 * <informalexample><programlisting>
860
 
 *  gdk-pixbuf-csource --raw --name=myimage_inline myimage.png
861
 
 * </programlisting></informalexample>
862
 
 * 
863
 
 * For the typical case where the inline pixbuf is read-only static data,
864
 
 * you don't need to copy the pixel data unless you intend to write to
865
 
 * it, so you can pass %FALSE for @copy_pixels.  (If you pass 
866
 
 * <option>--rle</option> to <command>gdk-pixbuf-csource</command>, a copy 
867
 
 * will be made even if @copy_pixels is %FALSE, so using this option is 
868
 
 * generally a bad idea.)
869
 
 *
870
 
 * If you create a pixbuf from const inline data compiled into your
871
 
 * program, it's probably safe to ignore errors and disable length checks, 
872
 
 * since things will always succeed:
873
 
 * <informalexample><programlisting>
874
 
 * pixbuf = gdk_pixbuf_new_from_inline (-1, myimage_inline, FALSE, NULL);
875
 
 * </programlisting></informalexample>
876
 
 *
877
 
 * For non-const inline data, you could get out of memory. For untrusted 
878
 
 * inline data located at runtime, you could have corrupt inline data in 
879
 
 * addition.
880
 
 *
881
 
 * Return value: A newly-created #GdkPixbuf structure with a reference,
882
 
 *   count of 1, or %NULL if an error occurred.
883
 
 **/
884
 
GdkPixbuf*
885
 
gdk_pixbuf_new_from_inline (gint          data_length,
886
 
                            const guint8 *data,
887
 
                            gboolean      copy_pixels,
888
 
                            GError      **error)
889
 
{
890
 
  GdkPixdata pixdata;
891
 
 
892
 
  if (data_length != -1)
893
 
    g_return_val_if_fail (data_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
894
 
  g_return_val_if_fail (data != NULL, NULL);
895
 
 
896
 
  if (!gdk_pixdata_deserialize (&pixdata, data_length, data, error))
897
 
    return NULL;
898
 
 
899
 
  return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
900
 
}
901
 
 
902
 
#define __GDK_PIXDATA_C__
903
 
#include "gdk-pixbuf-aliasdef.c"