~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/base/pixel-surround.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify
18
18
 
19
19
#include "config.h"
20
20
 
 
21
#include <string.h>
 
22
 
21
23
#include <glib-object.h>
22
24
 
23
25
#include "base-types.h"
28
30
#include "tile.h"
29
31
 
30
32
 
31
 
void
32
 
pixel_surround_init (PixelSurround *ps,
33
 
                     TileManager   *tm,
34
 
                     gint           w,
35
 
                     gint           h,
36
 
                     guchar         bg[MAX_CHANNELS])
37
 
{
38
 
  gint i;
39
 
 
40
 
  for (i = 0; i < MAX_CHANNELS; ++i)
41
 
    {
42
 
      ps->bg[i] = bg[i];
43
 
    }
44
 
 
45
 
  ps->tile       = NULL;
46
 
  ps->mgr        = tm;
47
 
  ps->bpp        = tile_manager_bpp (tm);
48
 
  ps->w          = w;
49
 
  ps->h          = h;
50
 
  /* make sure buffer is big enough */
51
 
  ps->buff_size  = w * h * ps->bpp;
52
 
  ps->buff       = g_new (guchar, ps->buff_size);
53
 
  ps->row_stride = 0;
54
 
}
55
 
 
56
 
guchar *
57
 
pixel_surround_lock (PixelSurround *ps,
58
 
                     gint           x,
59
 
                     gint           y)
60
 
{
61
 
  gint    i, j;
62
 
  guchar *k;
63
 
  guchar *ptr;
64
 
 
65
 
  ps->tile = tile_manager_get_tile (ps->mgr, x, y, TRUE, FALSE);
66
 
 
67
 
  i = x % TILE_WIDTH;
68
 
  j = y % TILE_HEIGHT;
69
 
 
70
 
  /* do we have the whole region? */
71
 
  if (ps->tile &&
72
 
      (i < (tile_ewidth(ps->tile) - ps->w)) &&
73
 
      (j < (tile_eheight(ps->tile) - ps->h)))
74
 
    {
75
 
      ps->row_stride = tile_ewidth (ps->tile) * ps->bpp;
76
 
      /* is this really the correct way? */
77
 
      return tile_data_pointer (ps->tile, i, j);
78
 
    }
79
 
 
80
 
  /* nope, do this the hard way (for now) */
81
 
  if (ps->tile)
82
 
    {
83
 
      tile_release (ps->tile, FALSE);
84
 
      ps->tile = NULL;
85
 
    }
86
 
 
87
 
  /* copy pixels, one by one */
88
 
  /* no, this is not the best way, but it's much better than before */
89
 
  ptr = ps->buff;
90
 
  for (j = y; j < y+ps->h; ++j)
91
 
    {
92
 
      for (i = x; i < x+ps->w; ++i)
93
 
        {
94
 
          Tile *tile = tile_manager_get_tile (ps->mgr, i, j, TRUE, FALSE);
95
 
 
96
 
          if (tile)
97
 
            {
98
 
              guchar *buff = tile_data_pointer (tile,
99
 
                                                i % TILE_WIDTH,
100
 
                                                j % TILE_HEIGHT);
101
 
 
102
 
              for (k = buff; k < buff+ps->bpp; ++k, ++ptr)
103
 
                {
104
 
                  *ptr = *k;
105
 
                }
106
 
              tile_release (tile, FALSE);
107
 
            }
108
 
          else
109
 
            {
110
 
              for (k = ps->bg; k < ps->bg+ps->bpp; ++k, ++ptr)
111
 
                {
112
 
                  *ptr = *k;
113
 
                }
114
 
            }
115
 
        }
116
 
    }
117
 
  ps->row_stride = ps->w * ps->bpp;
118
 
 
119
 
  return ps->buff;
120
 
}
121
 
 
122
 
gint
123
 
pixel_surround_rowstride (PixelSurround *ps)
124
 
{
125
 
  return ps->row_stride;
126
 
}
127
 
 
128
 
void
129
 
pixel_surround_release (PixelSurround *ps)
130
 
{
131
 
  /* always get new tile (for now), so release the old one */
132
 
  if (ps->tile)
133
 
    {
134
 
      tile_release (ps->tile, FALSE);
135
 
      ps->tile = NULL;
136
 
    }
137
 
}
138
 
 
139
 
void
140
 
pixel_surround_clear (PixelSurround *ps)
141
 
{
142
 
  if (ps->buff)
143
 
    {
144
 
      g_free (ps->buff);
145
 
      ps->buff = NULL;
146
 
      ps->buff_size = 0;
147
 
    }
 
33
struct _PixelSurround
 
34
{
 
35
  TileManager *mgr;        /*  tile manager to access tiles from    */
 
36
  gint         bpp;        /*  bytes per pixel in tile manager      */
 
37
  gint         w;          /*  width of pixel surround area         */
 
38
  gint         h;          /*  height of pixel surround area        */
 
39
  Tile        *tile;       /*  locked tile (may be NULL)            */
 
40
  gint         tile_x;     /*  origin of locked tile                */
 
41
  gint         tile_y;     /*  origin of locked tile                */
 
42
  gint         tile_w;     /*  width of locked tile                 */
 
43
  gint         tile_h;     /*  height of locked tile                */
 
44
  gint         rowstride;  /*  rowstride of buffers                 */
 
45
  guchar      *bg;         /*  buffer filled with background color  */
 
46
  guchar      *buf;        /*  buffer used for combining tile data  */
 
47
};
 
48
 
 
49
 
 
50
/*  inlining this function gives a few percent speedup  */
 
51
static inline const guchar *
 
52
pixel_surround_get_data (PixelSurround *surround,
 
53
                         gint           x,
 
54
                         gint           y,
 
55
                         gint          *w,
 
56
                         gint          *h,
 
57
                         gint          *rowstride)
 
58
{
 
59
  /*  do we still have a tile lock that we can use?  */
 
60
  if (surround->tile)
 
61
    {
 
62
      if (x < surround->tile_x || x >= surround->tile_x + surround->tile_w ||
 
63
          y < surround->tile_y || y >= surround->tile_y + surround->tile_h)
 
64
        {
 
65
          tile_release (surround->tile, FALSE);
 
66
          surround->tile = NULL;
 
67
        }
 
68
    }
 
69
 
 
70
  /*  if not, try to get one for the target pixel  */
 
71
  if (! surround->tile)
 
72
    {
 
73
      surround->tile = tile_manager_get_tile (surround->mgr, x, y, TRUE, FALSE);
 
74
 
 
75
      if (surround->tile)
 
76
        {
 
77
          /*  store offset and size of the locked tile  */
 
78
          surround->tile_x = x & ~(TILE_WIDTH - 1);
 
79
          surround->tile_y = y & ~(TILE_HEIGHT - 1);
 
80
          surround->tile_w = tile_ewidth (surround->tile);
 
81
          surround->tile_h = tile_eheight (surround->tile);
 
82
        }
 
83
    }
 
84
 
 
85
  if (surround->tile)
 
86
    {
 
87
      *w = surround->tile_x + surround->tile_w - x;
 
88
      *h = surround->tile_y + surround->tile_h - y;
 
89
 
 
90
      *rowstride = surround->tile_w * surround->bpp;
 
91
 
 
92
      return tile_data_pointer (surround->tile,
 
93
                                x % TILE_WIDTH, y % TILE_HEIGHT);
 
94
    }
 
95
  else
 
96
    {
 
97
      /*   return a pointer to a virtual background tile  */
 
98
      if (x < 0)
 
99
        *w = MIN (- x, surround->w);
 
100
      else
 
101
        *w = surround->w;
 
102
 
 
103
      if (y < 0)
 
104
        *h = MIN (- y, surround->h);
 
105
      else
 
106
        *h = surround->h;
 
107
 
 
108
      *rowstride = surround->rowstride;
 
109
 
 
110
      return surround->bg;
 
111
    }
 
112
}
 
113
 
 
114
/**
 
115
 * pixel_surround_new:
 
116
 * @tiles:  tile manager
 
117
 * @width:  width of surround region
 
118
 * @height: height of surround region
 
119
 * @bg:     color to use for pixels that are not covered by the tile manager
 
120
 *
 
121
 * Return value: a new #PixelSurround.
 
122
 */
 
123
PixelSurround *
 
124
pixel_surround_new (TileManager  *tiles,
 
125
                    gint          width,
 
126
                    gint          height,
 
127
                    const guchar  bg[MAX_CHANNELS])
 
128
{
 
129
  PixelSurround *surround;
 
130
  guchar        *dest;
 
131
  gint           pixels;
 
132
 
 
133
  g_return_val_if_fail (tiles != NULL, NULL);
 
134
 
 
135
  surround = g_new0 (PixelSurround, 1);
 
136
 
 
137
  surround->mgr       = tiles;
 
138
  surround->bpp       = tile_manager_bpp (tiles);
 
139
  surround->w         = width;
 
140
  surround->h         = height;
 
141
  surround->rowstride = width * surround->bpp;
 
142
  surround->bg        = g_new (guchar, surround->rowstride * height);
 
143
  surround->buf       = g_new (guchar, surround->rowstride * height);
 
144
 
 
145
  dest = surround->bg;
 
146
  pixels = width * height;
 
147
 
 
148
  while (pixels--)
 
149
    {
 
150
      gint i;
 
151
 
 
152
      for (i = 0; i < surround->bpp; i++)
 
153
        *dest++ = bg[i];
 
154
    }
 
155
 
 
156
  return surround;
 
157
}
 
158
 
 
159
/**
 
160
 * pixel_surround_lock:
 
161
 * @surround:  a #PixelSurround
 
162
 * @x:         X coordinate of upper left corner
 
163
 * @y:         Y coordinate of upper left corner
 
164
 * @rowstride: return location for rowstride
 
165
 *
 
166
 * Gives access to a region of pixels. The upper left corner is
 
167
 * specified by the @x and @y parameters. The size of the region
 
168
 * is determined by the dimensions given when creating the @surround.
 
169
 *
 
170
 * When you don't need to read from the pixels any longer, you should
 
171
 * unlock the @surround using pixel_surround_unlock(). If you need a
 
172
 * different region, just call pixel_surround_lock() again.
 
173
 *
 
174
 * Return value: pointer to pixel data (read-only)
 
175
 */
 
176
const guchar *
 
177
pixel_surround_lock (PixelSurround *surround,
 
178
                     gint           x,
 
179
                     gint           y,
 
180
                     gint          *rowstride)
 
181
{
 
182
  const guchar *src;
 
183
  gint          w, h;
 
184
 
 
185
  src = pixel_surround_get_data (surround, x, y, &w, &h, rowstride);
 
186
 
 
187
  if (w >= surround->w && h >= surround->h)
 
188
    {
 
189
      /*  return a pointer to the data if it covers the whole region  */
 
190
      return src;
 
191
    }
 
192
  else
 
193
    {
 
194
      /*  otherwise, copy region to our internal buffer  */
 
195
      guchar *dest = surround->buf;
 
196
      gint    inc  = surround->w;
 
197
      gint    i    = 0;
 
198
      gint    j    = 0;
 
199
 
 
200
      /*  These loops are somewhat twisted. The idea is to make as few
 
201
       *  calls to pixel_surround_get_data() as possible. Thus whenever we
 
202
       *  have source data, we copy all of it to the destination buffer.
 
203
       *  The inner loops that copy data are nested into outer loops that
 
204
       *  make sure that the destination area is completley filled.
 
205
       */
 
206
 
 
207
      /*  jump right into the loops since we already have source data  */
 
208
      goto start;
 
209
 
 
210
      while (i < surround->w)
 
211
        {
 
212
          dest = surround->buf + i * surround->bpp;
 
213
 
 
214
          for (j = 0; j < surround->h;)
 
215
            {
 
216
              gint rows;
 
217
 
 
218
              src = pixel_surround_get_data (surround,
 
219
                                             x + i, y + j, &w, &h, rowstride);
 
220
 
 
221
            start:
 
222
 
 
223
              w = MIN (w, surround->w - i);
 
224
              h = MIN (h, surround->h - j);
 
225
 
 
226
              rows = h;
 
227
 
 
228
              while (rows--)
 
229
                {
 
230
                  memcpy (dest, src, w * surround->bpp);
 
231
 
 
232
                  src += *rowstride;
 
233
                  dest += surround->rowstride;
 
234
                }
 
235
 
 
236
              j += h;
 
237
              inc = MIN (inc, w);
 
238
            }
 
239
 
 
240
          i += inc;
 
241
        }
 
242
    }
 
243
 
 
244
  *rowstride = surround->rowstride;
 
245
 
 
246
  return surround->buf;
 
247
}
 
248
 
 
249
/**
 
250
 * pixel_surround_release:
 
251
 * @surround: #PixelSurround
 
252
 *
 
253
 * Unlocks pixels locked by @surround. See pixel_surround_lock().
 
254
 */
 
255
void
 
256
pixel_surround_release (PixelSurround *surround)
 
257
{
 
258
  if (surround->tile)
 
259
    {
 
260
      tile_release (surround->tile, FALSE);
 
261
      surround->tile = NULL;
 
262
    }
 
263
}
 
264
 
 
265
/**
 
266
 * pixel_surround_destroy:
 
267
 * @surround: #PixelSurround
 
268
 *
 
269
 * Unlocks pixels and frees any resources allocated for @surround. You
 
270
 * must not use @surround any longer after calling this function.
 
271
 */
 
272
void
 
273
pixel_surround_destroy (PixelSurround *surround)
 
274
{
 
275
  g_return_if_fail (surround != NULL);
 
276
 
 
277
  pixel_surround_release (surround);
 
278
 
 
279
  g_free (surround->buf);
 
280
  g_free (surround->bg);
 
281
  g_free (surround);
148
282
}