Code

Disable the page selector when there's only one page
[inkscape.git] / src / libnr / nr-pixblock.cpp
1 #define __NR_PIXBLOCK_C__
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  *
9  * This code is in the Public Domain
10  */
12 #include <glib/gmem.h>
13 #include "nr-pixblock.h"
15 /// Size of buffer that needs no allocation (default 4).
16 #define NR_TINY_MAX sizeof (unsigned char *)
18 /**
19  * Pixbuf initialisation using homegrown memory handling ("pixelstore").
20  *
21  * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
22  * with each type having its own method of memory handling. After allocating
23  * memory, the buffer is cleared if the clear flag is set. Intended to
24  * reduce memory fragmentation.
25  * \param pb Pointer to the pixbuf struct.
26  * \param mode Indicates grayscale/RGB/RGBA.
27  * \param clear True if buffer should be cleared.
28  * \pre x1>=x0 && y1>=y0 && pb!=NULL
29  */
30 void
31 nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
32 {
33         int w, h, bpp;
34         size_t size;
36         w = x1 - x0;
37         h = y1 - y0;
38         bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
40         size = bpp * w * h;
42         if (size <= NR_TINY_MAX) {
43                 pb->size = NR_PIXBLOCK_SIZE_TINY;
44                 if (clear) memset (pb->data.p, 0x0, size);
45         } else if (size <= 4096) {
46                 pb->size = NR_PIXBLOCK_SIZE_4K;
47                 pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
48         } else if (size <= 16384) {
49                 pb->size = NR_PIXBLOCK_SIZE_16K;
50                 pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
51         } else if (size <= 65536) {
52                 pb->size = NR_PIXBLOCK_SIZE_64K;
53                 pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
54         } else if (size <= 262144) {
55                 pb->size = NR_PIXBLOCK_SIZE_256K;
56                 pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
57         } else if (size <= 1048576) {
58                 pb->size = NR_PIXBLOCK_SIZE_1M;
59                 pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
60         } else {
61                 pb->size = NR_PIXBLOCK_SIZE_BIG;
62              pb->data.px = NULL;
63                 if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA
64                             // pixels). It'll just bog the system down even if successful. FIXME:
65                             // Can anyone suggest something better than the magic number?
66                 g_warning ("%lu bytes requested for pixel buffer, I won't try to allocate that.", (long unsigned) size);
67                 return;
68              }
69                 pb->data.px = g_try_new (unsigned char, size);
70                 if (pb->data.px == NULL) { // memory allocation failed
71                 g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size);
72                 return;
73              }
74                 if (clear) memset (pb->data.px, 0x0, size);
75         }
77         pb->mode = mode;
78         pb->empty = 1;
79     pb->visible_area.x0 = pb->area.x0 = x0;
80     pb->visible_area.y0 = pb->area.y0 = y0;
81     pb->visible_area.x1 = pb->area.x1 = x1;
82     pb->visible_area.y1 = pb->area.y1 = y1;
83         pb->rs = bpp * w;
84 }
86 /**
87  * Pixbuf initialisation using g_new.
88  *
89  * After allocating memory, the buffer is cleared if the clear flag is set.
90  * \param pb Pointer to the pixbuf struct.
91  * \param mode Indicates grayscale/RGB/RGBA.
92  * \param clear True if buffer should be cleared.
93  * \pre x1>=x0 && y1>=y0 && pb!=NULL
94  FIXME: currently unused except for nr_pixblock_new and pattern tiles, replace with _fast and delete?
95  */
96 void
97 nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
98 {
99         int w, h, bpp;
100         size_t size;
102         w = x1 - x0;
103         h = y1 - y0;
104         bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
106         size = bpp * w * h;
108         if (size <= NR_TINY_MAX) {
109                 pb->size = NR_PIXBLOCK_SIZE_TINY;
110                 if (clear) memset (pb->data.p, 0x0, size);
111         } else {
112                 pb->size = NR_PIXBLOCK_SIZE_BIG;
113                 pb->data.px = g_new (unsigned char, size);
114                 if (clear) memset (pb->data.px, 0x0, size);
115         }
117         pb->mode = mode;
118         pb->empty = 1;
119     pb->visible_area.x0 = pb->area.x0 = x0;
120     pb->visible_area.y0 = pb->area.y0 = y0;
121     pb->visible_area.x1 = pb->area.x1 = x1;
122     pb->visible_area.y1 = pb->area.y1 = y1;
123         pb->rs = bpp * w;
126 /**
127  * Pixbuf initialisation with preset values.
128  *
129  * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
130  * \param pb Pointer to the pixbuf struct.
131  * \param mode Indicates grayscale/RGB/RGBA.
132  * \param clear True if buffer should be cleared.
133  * \pre x1>=x0 && y1>=y0 && pb!=NULL
134  */
135 void
136 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)
138         int w, bpp;
140         w = x1 - x0;
141         bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
143         pb->size = NR_PIXBLOCK_SIZE_STATIC; 
144         pb->mode = mode;
145         pb->empty = empty;
146         pb->visible_area.x0 = pb->area.x0 = x0;
147         pb->visible_area.y0 = pb->area.y0 = y0;
148         pb->visible_area.x1 = pb->area.x1 = x1;
149         pb->visible_area.y1 = pb->area.y1 = y1;
150         pb->data.px = px;
151         pb->rs = rs;
153         g_assert (pb->data.px != NULL);
154         if (clear) {
155                 if (rs == bpp * w) {
156                         /// \todo How do you recognise if 
157                         /// px was an uncleared tiny buffer? 
158                         if (pb->data.px) 
159                                 memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
160                 } else {
161                         int y;
162                         for (y = y0; y < y1; y++) {
163                                 memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
164                         }
165                 }
166         }
169 /**
170  * Frees memory taken by pixel data in NRPixBlock.
171  * \param pb Pointer to pixblock.
172  * \pre pb and pb->data.px point to valid addresses.
173  *
174  * According to pb->size, one of the functions for freeing the pixelstore
175  * is called. May be called regardless of how pixbuf was set up.
176  */
177 void
178 nr_pixblock_release (NRPixBlock *pb)
180         switch (pb->size) {
181         case NR_PIXBLOCK_SIZE_TINY:
182                 break;
183         case NR_PIXBLOCK_SIZE_4K:
184                 nr_pixelstore_4K_free (pb->data.px);
185                 break;
186         case NR_PIXBLOCK_SIZE_16K:
187                 nr_pixelstore_16K_free (pb->data.px);
188                 break;
189         case NR_PIXBLOCK_SIZE_64K:
190                 nr_pixelstore_64K_free (pb->data.px);
191                 break;
192         case NR_PIXBLOCK_SIZE_256K:
193                 nr_pixelstore_256K_free (pb->data.px);
194                 break;
195         case NR_PIXBLOCK_SIZE_1M:
196                 nr_pixelstore_1M_free (pb->data.px);
197                 break;
198         case NR_PIXBLOCK_SIZE_BIG:
199                 g_free (pb->data.px);
200                 break;
201         case NR_PIXBLOCK_SIZE_STATIC:
202                 break;
203         default:
204                 break;
205         }
208 /**
209  * Allocates NRPixBlock and sets it up.
210  *
211  * \return Pointer to fresh pixblock.
212  * Calls g_new() and nr_pixblock_setup().
213 FIXME: currently unused, delete?
214  */
215 NRPixBlock *
216 nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
218         NRPixBlock *pb;
220         pb = g_new (NRPixBlock, 1);
222         nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
224         return pb;
227 /**
228  * Frees all memory taken by pixblock.
229  *
230  * \return NULL
231  */
232 NRPixBlock *
233 nr_pixblock_free (NRPixBlock *pb)
235         nr_pixblock_release (pb);
237         g_free (pb);
239         return NULL;
242 /* PixelStore operations */
244 #define NR_4K_BLOCK 32
245 static unsigned char **nr_4K_px = NULL;
246 static unsigned int nr_4K_len = 0;
247 static unsigned int nr_4K_size = 0;
249 unsigned char *
250 nr_pixelstore_4K_new (bool clear, unsigned char val)
252         unsigned char *px;
254         if (nr_4K_len != 0) {
255                 nr_4K_len -= 1;
256                 px = nr_4K_px[nr_4K_len];
257         } else {
258                 px = g_new (unsigned char, 4096);
259         }
260         
261         if (clear) memset (px, val, 4096);
263         return px;
266 void
267 nr_pixelstore_4K_free (unsigned char *px)
269         if (nr_4K_len == nr_4K_size) {
270                 nr_4K_size += NR_4K_BLOCK;
271                 nr_4K_px = g_renew (unsigned char *, nr_4K_px, nr_4K_size);
272         }
274         nr_4K_px[nr_4K_len] = px;
275         nr_4K_len += 1;
278 #define NR_16K_BLOCK 32
279 static unsigned char **nr_16K_px = NULL;
280 static unsigned int nr_16K_len = 0;
281 static unsigned int nr_16K_size = 0;
283 unsigned char *
284 nr_pixelstore_16K_new (bool clear, unsigned char val)
286         unsigned char *px;
288         if (nr_16K_len != 0) {
289                 nr_16K_len -= 1;
290                 px = nr_16K_px[nr_16K_len];
291         } else {
292                 px = g_new (unsigned char, 16384);
293         }
294         
295         if (clear) memset (px, val, 16384);
297         return px;
300 void
301 nr_pixelstore_16K_free (unsigned char *px)
303         if (nr_16K_len == nr_16K_size) {
304                 nr_16K_size += NR_16K_BLOCK;
305                 nr_16K_px = g_renew (unsigned char *, nr_16K_px, nr_16K_size);
306         }
308         nr_16K_px[nr_16K_len] = px;
309         nr_16K_len += 1;
312 #define NR_64K_BLOCK 32
313 static unsigned char **nr_64K_px = NULL;
314 static unsigned int nr_64K_len = 0;
315 static unsigned int nr_64K_size = 0;
317 unsigned char *
318 nr_pixelstore_64K_new (bool clear, unsigned char val)
320         unsigned char *px;
322         if (nr_64K_len != 0) {
323                 nr_64K_len -= 1;
324                 px = nr_64K_px[nr_64K_len];
325         } else {
326                 px = g_new (unsigned char, 65536);
327         }
329         if (clear) memset (px, val, 65536);
331         return px;
334 void
335 nr_pixelstore_64K_free (unsigned char *px)
337         if (nr_64K_len == nr_64K_size) {
338                 nr_64K_size += NR_64K_BLOCK;
339                 nr_64K_px = g_renew (unsigned char *, nr_64K_px, nr_64K_size);
340         }
342         nr_64K_px[nr_64K_len] = px;
343         nr_64K_len += 1;
346 #define NR_256K_BLOCK 32
347 #define NR_256K 262144
348 static unsigned char **nr_256K_px = NULL;
349 static unsigned int nr_256K_len = 0;
350 static unsigned int nr_256K_size = 0;
352 unsigned char *
353 nr_pixelstore_256K_new (bool clear, unsigned char val)
355         unsigned char *px;
357         if (nr_256K_len != 0) {
358                 nr_256K_len -= 1;
359                 px = nr_256K_px[nr_256K_len];
360         } else {
361            px = g_new (unsigned char, NR_256K);
362         }
364         if (clear) memset (px, val, NR_256K);
366         return px;
369 void
370 nr_pixelstore_256K_free (unsigned char *px)
372         if (nr_256K_len == nr_256K_size) {
373                 nr_256K_size += NR_256K_BLOCK;
374                 nr_256K_px = g_renew (unsigned char *, nr_256K_px, nr_256K_size);
375         }
377         nr_256K_px[nr_256K_len] = px;
378         nr_256K_len += 1;
381 #define NR_1M_BLOCK 32
382 #define NR_1M 1048576
383 static unsigned char **nr_1M_px = NULL;
384 static unsigned int nr_1M_len = 0;
385 static unsigned int nr_1M_size = 0;
387 unsigned char *
388 nr_pixelstore_1M_new (bool clear, unsigned char val)
390         unsigned char *px;
392         if (nr_1M_len != 0) {
393                 nr_1M_len -= 1;
394                 px = nr_1M_px[nr_1M_len];
395         } else {
396            px = g_new (unsigned char, NR_1M);
397         }
399         if (clear) memset (px, val, NR_1M);
401         return px;
404 void
405 nr_pixelstore_1M_free (unsigned char *px)
407         if (nr_1M_len == nr_1M_size) {
408                 nr_1M_size += NR_1M_BLOCK;
409                 nr_1M_px = g_renew (unsigned char *, nr_1M_px, nr_1M_size);
410         }
412         nr_1M_px[nr_1M_len] = px;
413         nr_1M_len += 1;
416 /*
417   Local Variables:
418   mode:c++
419   c-file-style:"stroustrup"
420   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
421   indent-tabs-mode:nil
422   fill-column:99
423   End:
424 */
425 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :