summaryrefslogtreecommitdiffstats
path: root/src/libnr/nr-pixblock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnr/nr-pixblock.cpp')
-rw-r--r--src/libnr/nr-pixblock.cpp411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/libnr/nr-pixblock.cpp b/src/libnr/nr-pixblock.cpp
new file mode 100644
index 000000000..9b1ff2752
--- /dev/null
+++ b/src/libnr/nr-pixblock.cpp
@@ -0,0 +1,411 @@
+#define __NR_PIXBLOCK_C__
+
+/** \file
+ * \brief Allocation/Setup of NRPixBlock objects. Pixel store functions.
+ *
+ * Authors:
+ * (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * This code is in the Public Domain
+ */
+
+#include "nr-pixblock.h"
+
+/// Size of buffer that needs no allocation (default 4).
+#define NR_TINY_MAX sizeof (unsigned char *)
+
+/**
+ * Pixbuf initialisation using homegrown memory handling ("pixelstore").
+ *
+ * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
+ * with each type having its own method of memory handling. After allocating
+ * memory, the buffer is cleared if the clear flag is set. Intended to
+ * reduce memory fragmentation.
+ * \param pb Pointer to the pixbuf struct.
+ * \param mode Indicates grayscale/RGB/RGBA.
+ * \param clear True if buffer should be cleared.
+ * \pre x1>=x0 && y1>=y0 && pb!=NULL
+ */
+void
+nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
+{
+ int w, h, bpp;
+ size_t size;
+
+ w = x1 - x0;
+ h = y1 - y0;
+ bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+
+ size = bpp * w * h;
+
+ if (size <= NR_TINY_MAX) {
+ pb->size = NR_PIXBLOCK_SIZE_TINY;
+ if (clear) memset (pb->data.p, 0x0, size);
+ } else if (size <= 4096) {
+ pb->size = NR_PIXBLOCK_SIZE_4K;
+ pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
+ } else if (size <= 16384) {
+ pb->size = NR_PIXBLOCK_SIZE_16K;
+ pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
+ } else if (size <= 65536) {
+ pb->size = NR_PIXBLOCK_SIZE_64K;
+ pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
+ } else if (size <= 262144) {
+ pb->size = NR_PIXBLOCK_SIZE_256K;
+ pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
+ } else if (size <= 1048576) {
+ pb->size = NR_PIXBLOCK_SIZE_1M;
+ pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
+ } else {
+ pb->size = NR_PIXBLOCK_SIZE_BIG;
+ pb->data.px = nr_new (unsigned char, size);
+ if (clear) memset (pb->data.px, 0x0, size);
+ }
+
+ pb->mode = mode;
+ pb->empty = 1;
+ pb->area.x0 = x0;
+ pb->area.y0 = y0;
+ pb->area.x1 = x1;
+ pb->area.y1 = y1;
+ pb->rs = bpp * w;
+}
+
+/**
+ * Pixbuf initialisation using nr_new.
+ *
+ * After allocating memory, the buffer is cleared if the clear flag is set.
+ * \param pb Pointer to the pixbuf struct.
+ * \param mode Indicates grayscale/RGB/RGBA.
+ * \param clear True if buffer should be cleared.
+ * \pre x1>=x0 && y1>=y0 && pb!=NULL
+ */
+void
+nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
+{
+ int w, h, bpp;
+ size_t size;
+
+ w = x1 - x0;
+ h = y1 - y0;
+ bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+
+ size = bpp * w * h;
+
+ if (size <= NR_TINY_MAX) {
+ pb->size = NR_PIXBLOCK_SIZE_TINY;
+ if (clear) memset (pb->data.p, 0x0, size);
+ } else {
+ pb->size = NR_PIXBLOCK_SIZE_BIG;
+ pb->data.px = nr_new (unsigned char, size);
+ if (clear) memset (pb->data.px, 0x0, size);
+ }
+
+ pb->mode = mode;
+ pb->empty = 1;
+ pb->area.x0 = x0;
+ pb->area.y0 = y0;
+ pb->area.x1 = x1;
+ pb->area.y1 = y1;
+ pb->rs = bpp * w;
+}
+
+/**
+ * Pixbuf initialisation with preset values.
+ *
+ * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
+ * \param pb Pointer to the pixbuf struct.
+ * \param mode Indicates grayscale/RGB/RGBA.
+ * \param clear True if buffer should be cleared.
+ * \pre x1>=x0 && y1>=y0 && pb!=NULL
+ */
+void
+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)
+{
+ int w, bpp;
+
+ w = x1 - x0;
+ bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+
+ pb->size = NR_PIXBLOCK_SIZE_STATIC;
+ pb->mode = mode;
+ pb->empty = empty;
+ pb->area.x0 = x0;
+ pb->area.y0 = y0;
+ pb->area.x1 = x1;
+ pb->area.y1 = y1;
+ pb->data.px = px;
+ pb->rs = rs;
+
+ g_assert (pb->data.px != NULL);
+ if (clear) {
+ if (rs == bpp * w) {
+ /// \todo How do you recognise if
+ /// px was an uncleared tiny buffer?
+ if (pb->data.px)
+ memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
+ } else {
+ int y;
+ for (y = y0; y < y1; y++) {
+ memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
+ }
+ }
+ }
+}
+
+/**
+ * Frees memory taken by pixel data in NRPixBlock.
+ * \param pb Pointer to pixblock.
+ * \pre pb and pb->data.px point to valid addresses.
+ *
+ * According to pb->size, one of the functions for freeing the pixelstore
+ * is called. May be called regardless of how pixbuf was set up.
+ */
+void
+nr_pixblock_release (NRPixBlock *pb)
+{
+ switch (pb->size) {
+ case NR_PIXBLOCK_SIZE_TINY:
+ break;
+ case NR_PIXBLOCK_SIZE_4K:
+ nr_pixelstore_4K_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_16K:
+ nr_pixelstore_16K_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_64K:
+ nr_pixelstore_64K_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_256K:
+ nr_pixelstore_256K_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_1M:
+ nr_pixelstore_1M_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_BIG:
+ nr_free (pb->data.px);
+ break;
+ case NR_PIXBLOCK_SIZE_STATIC:
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Allocates NRPixBlock and sets it up.
+ *
+ * \return Pointer to fresh pixblock.
+ * Calls nr_new() and nr_pixblock_setup().
+ */
+NRPixBlock *
+nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
+{
+ NRPixBlock *pb;
+
+ pb = nr_new (NRPixBlock, 1);
+
+ nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
+
+ return pb;
+}
+
+/**
+ * Frees all memory taken by pixblock.
+ *
+ * \return NULL
+ */
+NRPixBlock *
+nr_pixblock_free (NRPixBlock *pb)
+{
+ nr_pixblock_release (pb);
+
+ nr_free (pb);
+
+ return NULL;
+}
+
+/* PixelStore operations */
+
+#define NR_4K_BLOCK 32
+static unsigned char **nr_4K_px = NULL;
+static unsigned int nr_4K_len = 0;
+static unsigned int nr_4K_size = 0;
+
+unsigned char *
+nr_pixelstore_4K_new (bool clear, unsigned char val)
+{
+ unsigned char *px;
+
+ if (nr_4K_len != 0) {
+ nr_4K_len -= 1;
+ px = nr_4K_px[nr_4K_len];
+ } else {
+ px = nr_new (unsigned char, 4096);
+ }
+
+ if (clear) memset (px, val, 4096);
+
+ return px;
+}
+
+void
+nr_pixelstore_4K_free (unsigned char *px)
+{
+ if (nr_4K_len == nr_4K_size) {
+ nr_4K_size += NR_4K_BLOCK;
+ nr_4K_px = nr_renew (nr_4K_px, unsigned char *, nr_4K_size);
+ }
+
+ nr_4K_px[nr_4K_len] = px;
+ nr_4K_len += 1;
+}
+
+#define NR_16K_BLOCK 32
+static unsigned char **nr_16K_px = NULL;
+static unsigned int nr_16K_len = 0;
+static unsigned int nr_16K_size = 0;
+
+unsigned char *
+nr_pixelstore_16K_new (bool clear, unsigned char val)
+{
+ unsigned char *px;
+
+ if (nr_16K_len != 0) {
+ nr_16K_len -= 1;
+ px = nr_16K_px[nr_16K_len];
+ } else {
+ px = nr_new (unsigned char, 16384);
+ }
+
+ if (clear) memset (px, val, 16384);
+
+ return px;
+}
+
+void
+nr_pixelstore_16K_free (unsigned char *px)
+{
+ if (nr_16K_len == nr_16K_size) {
+ nr_16K_size += NR_16K_BLOCK;
+ nr_16K_px = nr_renew (nr_16K_px, unsigned char *, nr_16K_size);
+ }
+
+ nr_16K_px[nr_16K_len] = px;
+ nr_16K_len += 1;
+}
+
+#define NR_64K_BLOCK 32
+static unsigned char **nr_64K_px = NULL;
+static unsigned int nr_64K_len = 0;
+static unsigned int nr_64K_size = 0;
+
+unsigned char *
+nr_pixelstore_64K_new (bool clear, unsigned char val)
+{
+ unsigned char *px;
+
+ if (nr_64K_len != 0) {
+ nr_64K_len -= 1;
+ px = nr_64K_px[nr_64K_len];
+ } else {
+ px = nr_new (unsigned char, 65536);
+ }
+
+ if (clear) memset (px, val, 65536);
+
+ return px;
+}
+
+void
+nr_pixelstore_64K_free (unsigned char *px)
+{
+ if (nr_64K_len == nr_64K_size) {
+ nr_64K_size += NR_64K_BLOCK;
+ nr_64K_px = nr_renew (nr_64K_px, unsigned char *, nr_64K_size);
+ }
+
+ nr_64K_px[nr_64K_len] = px;
+ nr_64K_len += 1;
+}
+
+#define NR_256K_BLOCK 32
+#define NR_256K 262144
+static unsigned char **nr_256K_px = NULL;
+static unsigned int nr_256K_len = 0;
+static unsigned int nr_256K_size = 0;
+
+unsigned char *
+nr_pixelstore_256K_new (bool clear, unsigned char val)
+{
+ unsigned char *px;
+
+ if (nr_256K_len != 0) {
+ nr_256K_len -= 1;
+ px = nr_256K_px[nr_256K_len];
+ } else {
+ px = nr_new (unsigned char, NR_256K);
+ }
+
+ if (clear) memset (px, val, NR_256K);
+
+ return px;
+}
+
+void
+nr_pixelstore_256K_free (unsigned char *px)
+{
+ if (nr_256K_len == nr_256K_size) {
+ nr_256K_size += NR_256K_BLOCK;
+ nr_256K_px = nr_renew (nr_256K_px, unsigned char *, nr_256K_size);
+ }
+
+ nr_256K_px[nr_256K_len] = px;
+ nr_256K_len += 1;
+}
+
+#define NR_1M_BLOCK 32
+#define NR_1M 1048576
+static unsigned char **nr_1M_px = NULL;
+static unsigned int nr_1M_len = 0;
+static unsigned int nr_1M_size = 0;
+
+unsigned char *
+nr_pixelstore_1M_new (bool clear, unsigned char val)
+{
+ unsigned char *px;
+
+ if (nr_1M_len != 0) {
+ nr_1M_len -= 1;
+ px = nr_1M_px[nr_1M_len];
+ } else {
+ px = nr_new (unsigned char, NR_1M);
+ }
+
+ if (clear) memset (px, val, NR_1M);
+
+ return px;
+}
+
+void
+nr_pixelstore_1M_free (unsigned char *px)
+{
+ if (nr_1M_len == nr_1M_size) {
+ nr_1M_size += NR_1M_BLOCK;
+ nr_1M_px = nr_renew (nr_1M_px, unsigned char *, nr_1M_size);
+ }
+
+ nr_1M_px[nr_1M_len] = px;
+ nr_1M_len += 1;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :