~ubuntu-branches/ubuntu/oneiric/inkscape/oneiric-updates

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/libnr/nr-pixblock.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define __NR_PIXBLOCK_C__
 
2
 
 
3
/** \file
 
4
 * \brief Allocation/Setup of NRPixBlock objects. Pixel store functions.
 
5
 *
 
6
 * Authors:
 
7
 *   (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com>
 
8
 *   2008, Jasper van de Gronde <th.v.d.gonde@hccnet.nl>
 
9
 *
 
10
 * This code is in the Public Domain
 
11
 */
 
12
 
 
13
#include <cstring>
 
14
#include <string>
 
15
#include <string.h>
 
16
#include <glib/gmem.h>
 
17
#include "nr-pixblock.h"
 
18
 
 
19
/// Size of buffer that needs no allocation (default 4).
 
20
#define NR_TINY_MAX sizeof (unsigned char *)
 
21
 
 
22
/**
 
23
 * Pixbuf initialisation using homegrown memory handling ("pixelstore").
 
24
 *
 
25
 * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
 
26
 * with each type having its own method of memory handling. After allocating
 
27
 * memory, the buffer is cleared if the clear flag is set. Intended to
 
28
 * reduce memory fragmentation.
 
29
 * \param pb Pointer to the pixbuf struct.
 
30
 * \param mode Indicates grayscale/RGB/RGBA.
 
31
 * \param clear True if buffer should be cleared.
 
32
 * \pre x1>=x0 && y1>=y0 && pb!=NULL
 
33
 */
 
34
void
 
35
nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
 
36
{
 
37
        int w, h, bpp;
 
38
        size_t size;
 
39
 
 
40
        w = x1 - x0;
 
41
        h = y1 - y0;
 
42
        bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
43
 
 
44
        size = bpp * w * h;
 
45
 
 
46
        if (size <= NR_TINY_MAX) {
 
47
                pb->size = NR_PIXBLOCK_SIZE_TINY;
 
48
                if (clear) memset (pb->data.p, 0x0, size);
 
49
        } else if (size <= 4096) {
 
50
                pb->size = NR_PIXBLOCK_SIZE_4K;
 
51
                pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
 
52
        } else if (size <= 16384) {
 
53
                pb->size = NR_PIXBLOCK_SIZE_16K;
 
54
                pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
 
55
        } else if (size <= 65536) {
 
56
                pb->size = NR_PIXBLOCK_SIZE_64K;
 
57
                pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
 
58
        } else if (size <= 262144) {
 
59
                pb->size = NR_PIXBLOCK_SIZE_256K;
 
60
                pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
 
61
        } else if (size <= 1048576) {
 
62
                pb->size = NR_PIXBLOCK_SIZE_1M;
 
63
                pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
 
64
        } else {
 
65
                pb->size = NR_PIXBLOCK_SIZE_BIG;
 
66
             pb->data.px = NULL;
 
67
                if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA
 
68
                            // pixels). It'll just bog the system down even if successful. FIXME:
 
69
                            // Can anyone suggest something better than the magic number?
 
70
                g_warning ("%lu bytes requested for pixel buffer, I won't try to allocate that.", (long unsigned) size);
 
71
                return;
 
72
             }
 
73
                pb->data.px = g_try_new (unsigned char, size);
 
74
                if (pb->data.px == NULL) { // memory allocation failed
 
75
                g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size);
 
76
                return;
 
77
             }
 
78
                if (clear) memset (pb->data.px, 0x0, size);
 
79
        }
 
80
 
 
81
        pb->mode = mode;
 
82
        pb->empty = 1;
 
83
    pb->visible_area.x0 = pb->area.x0 = x0;
 
84
    pb->visible_area.y0 = pb->area.y0 = y0;
 
85
    pb->visible_area.x1 = pb->area.x1 = x1;
 
86
    pb->visible_area.y1 = pb->area.y1 = y1;
 
87
        pb->rs = bpp * w;
 
88
}
 
89
 
 
90
/**
 
91
 * Pixbuf initialisation using g_new.
 
92
 *
 
93
 * After allocating memory, the buffer is cleared if the clear flag is set.
 
94
 * \param pb Pointer to the pixbuf struct.
 
95
 * \param mode Indicates grayscale/RGB/RGBA.
 
96
 * \param clear True if buffer should be cleared.
 
97
 * \pre x1>=x0 && y1>=y0 && pb!=NULL
 
98
 FIXME: currently unused except for nr_pixblock_new and pattern tiles, replace with _fast and delete?
 
99
 */
 
100
void
 
101
nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
 
102
{
 
103
        int w, h, bpp;
 
104
        size_t size;
 
105
 
 
106
        w = x1 - x0;
 
107
        h = y1 - y0;
 
108
        bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
109
 
 
110
        size = bpp * w * h;
 
111
 
 
112
        if (size <= NR_TINY_MAX) {
 
113
                pb->size = NR_PIXBLOCK_SIZE_TINY;
 
114
                if (clear) memset (pb->data.p, 0x0, size);
 
115
        } else {
 
116
                pb->size = NR_PIXBLOCK_SIZE_BIG;
 
117
                pb->data.px = g_new (unsigned char, size);
 
118
                if (clear) memset (pb->data.px, 0x0, size);
 
119
        }
 
120
 
 
121
        pb->mode = mode;
 
122
        pb->empty = 1;
 
123
    pb->visible_area.x0 = pb->area.x0 = x0;
 
124
    pb->visible_area.y0 = pb->area.y0 = y0;
 
125
    pb->visible_area.x1 = pb->area.x1 = x1;
 
126
    pb->visible_area.y1 = pb->area.y1 = y1;
 
127
        pb->rs = bpp * w;
 
128
}
 
129
 
 
130
/**
 
131
 * Pixbuf initialisation with preset values.
 
132
 *
 
133
 * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
 
134
 * \param pb Pointer to the pixbuf struct.
 
135
 * \param mode Indicates grayscale/RGB/RGBA.
 
136
 * \param clear True if buffer should be cleared.
 
137
 * \pre x1>=x0 && y1>=y0 && pb!=NULL
 
138
 */
 
139
void
 
140
nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, unsigned char *px, int rs, bool empty, bool clear)
 
141
{
 
142
        int w, bpp;
 
143
 
 
144
        w = x1 - x0;
 
145
        bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
146
 
 
147
        pb->size = NR_PIXBLOCK_SIZE_STATIC; 
 
148
        pb->mode = mode;
 
149
        pb->empty = empty;
 
150
        pb->visible_area.x0 = pb->area.x0 = x0;
 
151
        pb->visible_area.y0 = pb->area.y0 = y0;
 
152
        pb->visible_area.x1 = pb->area.x1 = x1;
 
153
        pb->visible_area.y1 = pb->area.y1 = y1;
 
154
        pb->data.px = px;
 
155
        pb->rs = rs;
 
156
 
 
157
        g_assert (pb->data.px != NULL);
 
158
        if (clear) {
 
159
                if (rs == bpp * w) {
 
160
                        /// \todo How do you recognise if 
 
161
                        /// px was an uncleared tiny buffer? 
 
162
                        if (pb->data.px) 
 
163
                                memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
 
164
                } else {
 
165
                        int y;
 
166
                        for (y = y0; y < y1; y++) {
 
167
                                memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
 
168
                        }
 
169
                }
 
170
        }
 
171
}
 
172
 
 
173
/**
 
174
 * Frees memory taken by pixel data in NRPixBlock.
 
175
 * \param pb Pointer to pixblock.
 
176
 * \pre pb and pb->data.px point to valid addresses.
 
177
 *
 
178
 * According to pb->size, one of the functions for freeing the pixelstore
 
179
 * is called. May be called regardless of how pixbuf was set up.
 
180
 */
 
181
void
 
182
nr_pixblock_release (NRPixBlock *pb)
 
183
{
 
184
        switch (pb->size) {
 
185
        case NR_PIXBLOCK_SIZE_TINY:
 
186
                break;
 
187
        case NR_PIXBLOCK_SIZE_4K:
 
188
                nr_pixelstore_4K_free (pb->data.px);
 
189
                break;
 
190
        case NR_PIXBLOCK_SIZE_16K:
 
191
                nr_pixelstore_16K_free (pb->data.px);
 
192
                break;
 
193
        case NR_PIXBLOCK_SIZE_64K:
 
194
                nr_pixelstore_64K_free (pb->data.px);
 
195
                break;
 
196
        case NR_PIXBLOCK_SIZE_256K:
 
197
                nr_pixelstore_256K_free (pb->data.px);
 
198
                break;
 
199
        case NR_PIXBLOCK_SIZE_1M:
 
200
                nr_pixelstore_1M_free (pb->data.px);
 
201
                break;
 
202
        case NR_PIXBLOCK_SIZE_BIG:
 
203
                g_free (pb->data.px);
 
204
                break;
 
205
        case NR_PIXBLOCK_SIZE_STATIC:
 
206
                break;
 
207
        default:
 
208
                break;
 
209
        }
 
210
}
 
211
 
 
212
/**
 
213
 * Allocates NRPixBlock and sets it up.
 
214
 *
 
215
 * \return Pointer to fresh pixblock.
 
216
 * Calls g_new() and nr_pixblock_setup().
 
217
FIXME: currently unused, delete? JG: Should be used more often! (To simplify memory management.)
 
218
 */
 
219
NRPixBlock *
 
220
nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
 
221
{
 
222
        NRPixBlock *pb;
 
223
 
 
224
        pb = g_new (NRPixBlock, 1);
 
225
    if (!pb) return 0;
 
226
 
 
227
        nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
 
228
    if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) {
 
229
        g_free(pb);
 
230
        return 0;
 
231
    }
 
232
 
 
233
        return pb;
 
234
}
 
235
 
 
236
/**
 
237
 * Allocates NRPixBlock and sets it up.
 
238
 *
 
239
 * \return Pointer to fresh pixblock.
 
240
 * Calls g_new() and nr_pixblock_setup().
 
241
 */
 
242
NRPixBlock *
 
243
nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
 
244
{
 
245
    NRPixBlock *pb;
 
246
 
 
247
    pb = g_new (NRPixBlock, 1);
 
248
    if (!pb) return 0;
 
249
 
 
250
    nr_pixblock_setup_fast (pb, mode, x0, y0, x1, y1, clear);
 
251
    if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) {
 
252
        g_free(pb);
 
253
        return 0;
 
254
    }
 
255
 
 
256
    return pb;
 
257
}
 
258
 
 
259
/**
 
260
 * Frees all memory taken by pixblock.
 
261
 *
 
262
 * \return NULL
 
263
 */
 
264
NRPixBlock *
 
265
nr_pixblock_free (NRPixBlock *pb)
 
266
{
 
267
        nr_pixblock_release (pb);
 
268
 
 
269
        g_free (pb);
 
270
 
 
271
        return NULL;
 
272
}
 
273
 
 
274
/* PixelStore operations */
 
275
 
 
276
#define NR_4K_BLOCK 32
 
277
static unsigned char **nr_4K_px = NULL;
 
278
static unsigned int nr_4K_len = 0;
 
279
static unsigned int nr_4K_size = 0;
 
280
 
 
281
unsigned char *
 
282
nr_pixelstore_4K_new (bool clear, unsigned char val)
 
283
{
 
284
        unsigned char *px;
 
285
 
 
286
        if (nr_4K_len != 0) {
 
287
                nr_4K_len -= 1;
 
288
                px = nr_4K_px[nr_4K_len];
 
289
        } else {
 
290
                px = g_new (unsigned char, 4096);
 
291
        }
 
292
        
 
293
        if (clear) memset (px, val, 4096);
 
294
 
 
295
        return px;
 
296
}
 
297
 
 
298
void
 
299
nr_pixelstore_4K_free (unsigned char *px)
 
300
{
 
301
        if (nr_4K_len == nr_4K_size) {
 
302
                nr_4K_size += NR_4K_BLOCK;
 
303
                nr_4K_px = g_renew (unsigned char *, nr_4K_px, nr_4K_size);
 
304
        }
 
305
 
 
306
        nr_4K_px[nr_4K_len] = px;
 
307
        nr_4K_len += 1;
 
308
}
 
309
 
 
310
#define NR_16K_BLOCK 32
 
311
static unsigned char **nr_16K_px = NULL;
 
312
static unsigned int nr_16K_len = 0;
 
313
static unsigned int nr_16K_size = 0;
 
314
 
 
315
unsigned char *
 
316
nr_pixelstore_16K_new (bool clear, unsigned char val)
 
317
{
 
318
        unsigned char *px;
 
319
 
 
320
        if (nr_16K_len != 0) {
 
321
                nr_16K_len -= 1;
 
322
                px = nr_16K_px[nr_16K_len];
 
323
        } else {
 
324
                px = g_new (unsigned char, 16384);
 
325
        }
 
326
        
 
327
        if (clear) memset (px, val, 16384);
 
328
 
 
329
        return px;
 
330
}
 
331
 
 
332
void
 
333
nr_pixelstore_16K_free (unsigned char *px)
 
334
{
 
335
        if (nr_16K_len == nr_16K_size) {
 
336
                nr_16K_size += NR_16K_BLOCK;
 
337
                nr_16K_px = g_renew (unsigned char *, nr_16K_px, nr_16K_size);
 
338
        }
 
339
 
 
340
        nr_16K_px[nr_16K_len] = px;
 
341
        nr_16K_len += 1;
 
342
}
 
343
 
 
344
#define NR_64K_BLOCK 32
 
345
static unsigned char **nr_64K_px = NULL;
 
346
static unsigned int nr_64K_len = 0;
 
347
static unsigned int nr_64K_size = 0;
 
348
 
 
349
unsigned char *
 
350
nr_pixelstore_64K_new (bool clear, unsigned char val)
 
351
{
 
352
        unsigned char *px;
 
353
 
 
354
        if (nr_64K_len != 0) {
 
355
                nr_64K_len -= 1;
 
356
                px = nr_64K_px[nr_64K_len];
 
357
        } else {
 
358
                px = g_new (unsigned char, 65536);
 
359
        }
 
360
 
 
361
        if (clear) memset (px, val, 65536);
 
362
 
 
363
        return px;
 
364
}
 
365
 
 
366
void
 
367
nr_pixelstore_64K_free (unsigned char *px)
 
368
{
 
369
        if (nr_64K_len == nr_64K_size) {
 
370
                nr_64K_size += NR_64K_BLOCK;
 
371
                nr_64K_px = g_renew (unsigned char *, nr_64K_px, nr_64K_size);
 
372
        }
 
373
 
 
374
        nr_64K_px[nr_64K_len] = px;
 
375
        nr_64K_len += 1;
 
376
}
 
377
 
 
378
#define NR_256K_BLOCK 32
 
379
#define NR_256K 262144
 
380
static unsigned char **nr_256K_px = NULL;
 
381
static unsigned int nr_256K_len = 0;
 
382
static unsigned int nr_256K_size = 0;
 
383
 
 
384
unsigned char *
 
385
nr_pixelstore_256K_new (bool clear, unsigned char val)
 
386
{
 
387
        unsigned char *px;
 
388
 
 
389
        if (nr_256K_len != 0) {
 
390
                nr_256K_len -= 1;
 
391
                px = nr_256K_px[nr_256K_len];
 
392
        } else {
 
393
           px = g_new (unsigned char, NR_256K);
 
394
        }
 
395
 
 
396
        if (clear) memset (px, val, NR_256K);
 
397
 
 
398
        return px;
 
399
}
 
400
 
 
401
void
 
402
nr_pixelstore_256K_free (unsigned char *px)
 
403
{
 
404
        if (nr_256K_len == nr_256K_size) {
 
405
                nr_256K_size += NR_256K_BLOCK;
 
406
                nr_256K_px = g_renew (unsigned char *, nr_256K_px, nr_256K_size);
 
407
        }
 
408
 
 
409
        nr_256K_px[nr_256K_len] = px;
 
410
        nr_256K_len += 1;
 
411
}
 
412
 
 
413
#define NR_1M_BLOCK 32
 
414
#define NR_1M 1048576
 
415
static unsigned char **nr_1M_px = NULL;
 
416
static unsigned int nr_1M_len = 0;
 
417
static unsigned int nr_1M_size = 0;
 
418
 
 
419
unsigned char *
 
420
nr_pixelstore_1M_new (bool clear, unsigned char val)
 
421
{
 
422
        unsigned char *px;
 
423
 
 
424
        if (nr_1M_len != 0) {
 
425
                nr_1M_len -= 1;
 
426
                px = nr_1M_px[nr_1M_len];
 
427
        } else {
 
428
           px = g_new (unsigned char, NR_1M);
 
429
        }
 
430
 
 
431
        if (clear) memset (px, val, NR_1M);
 
432
 
 
433
        return px;
 
434
}
 
435
 
 
436
void
 
437
nr_pixelstore_1M_free (unsigned char *px)
 
438
{
 
439
        if (nr_1M_len == nr_1M_size) {
 
440
                nr_1M_size += NR_1M_BLOCK;
 
441
                nr_1M_px = g_renew (unsigned char *, nr_1M_px, nr_1M_size);
 
442
        }
 
443
 
 
444
        nr_1M_px[nr_1M_len] = px;
 
445
        nr_1M_len += 1;
 
446
}
 
447
 
 
448
/*
 
449
  Local Variables:
 
450
  mode:c++
 
451
  c-file-style:"stroustrup"
 
452
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
453
  indent-tabs-mode:nil
 
454
  fill-column:99
 
455
  End:
 
456
*/
 
457
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :