summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdib Taraben <theadib@gmail.com>2011-01-17 22:17:48 +0000
committertheAdib <theadib@gmail.com>2011-01-17 22:17:48 +0000
commit38bfe781de137c7173df661a5b99cef685a86e46 (patch)
treef91cdf1afd59924adf180ea494d419e5728e88ff /src
parentTranslations. Indonesian translation update by Waluyo Adi Siswanto. (diff)
downloadinkscape-38bfe781de137c7173df661a5b99cef685a86e46.tar.gz
inkscape-38bfe781de137c7173df661a5b99cef685a86e46.zip
remove memory boundries on bitmap renderer, optimize memory usage
Fixed bugs: - https://launchpad.net/bugs/494115 (bzr r10009)
Diffstat (limited to 'src')
-rw-r--r--src/extension/internal/cairo-render-context.cpp38
-rw-r--r--src/extension/internal/cairo-renderer.cpp17
-rw-r--r--src/helper/pixbuf-ops.cpp14
-rw-r--r--src/libnr/nr-pixblock.cpp24
4 files changed, 75 insertions, 18 deletions
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index 18a654e27..b68105b30 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -516,7 +516,7 @@ CairoRenderContext::getClipMode(void) const
CairoRenderState*
CairoRenderContext::_createState(void)
{
- CairoRenderState *state = (CairoRenderState*)g_malloc(sizeof(CairoRenderState));
+ CairoRenderState *state = (CairoRenderState*)g_try_malloc(sizeof(CairoRenderState));
g_assert( state != NULL );
state->has_filtereffect = FALSE;
@@ -796,7 +796,7 @@ CairoRenderContext::setupSurface(double width, double height)
case CAIRO_SURFACE_TYPE_PDF:
surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height);
#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
- cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level);
+ cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level);
#endif
break;
#endif
@@ -1420,9 +1420,20 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi
if (_render_mode == RENDER_MODE_CLIP)
return true;
- guchar* px_rgba = (guchar*)g_malloc(4 * w * h);
- if (!px_rgba)
+ guchar* px_rgba = NULL;
+ guint64 size = 4L * (guint64)w * (guint64)h;
+
+ if(size < (guint64)G_MAXSIZE) {
+ px_rgba = (guchar*)g_try_malloc(4 * w * h);
+ if (!px_rgba) {
+ g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size);
+ return false;
+ }
+ } else {
+ g_warning ("the requested memory exceeds the system limit");
return false;
+ }
+
float opacity;
if (_state->merge_opacity)
@@ -1432,15 +1443,16 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi
// make a copy of the original pixbuf with premultiplied alpha
// if we pass the original pixbuf it will get messed up
+ /// @todo optimize this code, it costs a lot of time
for (unsigned i = 0; i < h; i++) {
+ guchar const *src = px + i * rs;
+ guint32 *dst = (guint32 *)(px_rgba + i * rs);
for (unsigned j = 0; j < w; j++) {
- guchar const *src = px + i * rs + j * 4;
- guint32 *dst = (guint32 *)(px_rgba + i * rs + j * 4);
guchar r, g, b, alpha_dst;
// calculate opacity-modified alpha
alpha_dst = src[3];
- if (opacity != 1.0 && _vector_based_target)
+ if ((opacity != 1.0) && _vector_based_target)
alpha_dst = (guchar)ceil((float)alpha_dst * opacity);
// premul alpha (needed because this will be undone by cairo-pdf)
@@ -1449,6 +1461,9 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi
b = src[2]*alpha_dst/255;
*dst = (((alpha_dst) << 24) | (((r)) << 16) | (((g)) << 8) | (b));
+
+ dst++; // pointer to 4byte variables
+ src += 4; // pointer to 1byte variables
}
}
@@ -1497,8 +1512,13 @@ CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoG
cairo_glyph_t glyph_array[GLYPH_ARRAY_SIZE];
cairo_glyph_t *glyphs = glyph_array;
unsigned int num_glyphs = glyphtext.size();
- if (num_glyphs > GLYPH_ARRAY_SIZE)
- glyphs = (cairo_glyph_t*)g_malloc(sizeof(cairo_glyph_t) * num_glyphs);
+ if (num_glyphs > GLYPH_ARRAY_SIZE) {
+ glyphs = (cairo_glyph_t*)g_try_malloc(sizeof(cairo_glyph_t) * num_glyphs);
+ if(glyphs == NULL) {
+ g_warning("CairorenderContext::_showGlyphs: can not allocate memory for %d glyphs.", num_glyphs);
+ return 0;
+ }
+ }
unsigned int num_invalid_glyphs = 0;
unsigned int i = 0; // is a counter for indexing the glyphs array, only counts the valid glyphs
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 67f9354d8..bc3c6c484 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -452,8 +452,23 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
Geom::OptRect bbox =
item->getBounds(item->i2d_affine(), SPItem::RENDERING_BBOX);
- if (!bbox) // no bbox, e.g. empty group
+ // no bbox, e.g. empty group
+ if (!bbox) {
return;
+ }
+
+ Geom::Rect docrect(Geom::Rect(Geom::Point(0, 0), SP_OBJECT(item)->document->getDimensions()));
+ Geom::Rect bboxrect(Geom::Rect(Geom::Point(bbox->min()[Geom::X], bbox->min()[Geom::Y]), Geom::Point(bbox->max()[Geom::X], bbox->max()[Geom::Y])));
+
+ Geom::OptRect _bbox = Geom::intersect(docrect, bboxrect);
+
+ // assign the object dimension clipped on the document, no need to draw on area not on canvas
+ bbox = _bbox;
+
+ // no bbox, e.g. empty group
+ if (!bbox) {
+ return;
+ }
// The width and height of the bitmap in pixels
unsigned width = (unsigned) floor ((bbox->max()[Geom::X] - bbox->min()[Geom::X]) * (res / PX_PER_IN));
diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp
index 69becad5d..7ce5c7dd2 100644
--- a/src/helper/pixbuf-ops.cpp
+++ b/src/helper/pixbuf-ops.cpp
@@ -91,6 +91,19 @@ sp_export_jpg_file(SPDocument *doc, gchar const *filename,
else return false;
}
+/**
+ generates a bitmap from given items
+ the bitmap is stored in RAM and not written to file
+ @param x0
+ @param y0
+ @param x1
+ @param y1
+ @param width
+ @param height
+ @param xdpi
+ @param ydpi
+ @return the created GdkPixbuf structure or NULL if no memory is allocable
+*/
GdkPixbuf*
sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/,
double x0, double y0, double x1, double y1,
@@ -164,6 +177,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/,
dtc[2] = NR_RGBA32_B(bgcolor);
dtc[3] = NR_RGBA32_A(bgcolor);
+ // fill pixelblock using background colour
for (gsize fy = 0; fy < height; fy++) {
guchar *p = NR_PIXBLOCK_PX(&B) + fy * (gsize)B.rs;
for (unsigned int fx = 0; fx < width; fx++) {
diff --git a/src/libnr/nr-pixblock.cpp b/src/libnr/nr-pixblock.cpp
index d69b6fe54..b95d8db8d 100644
--- a/src/libnr/nr-pixblock.cpp
+++ b/src/libnr/nr-pixblock.cpp
@@ -41,6 +41,13 @@ nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, i
h = y1 - y0;
bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+ guint64 sizel = (guint64)bpp * (guint64)w * (guint64)h;
+
+ if(sizel > (guint64)G_MAXSIZE) {
+ g_warning ("the requested memory exceeds the system limit");
+ return;
+ }
+
size = bpp * w * h;
if (size <= NR_TINY_MAX) {
@@ -67,8 +74,9 @@ nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, i
if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA
// pixels). It'll just bog the system down even if successful. FIXME:
// Can anyone suggest something better than the magic number?
- g_warning ("%lu bytes requested for pixel buffer, I won't try to allocate that.", (long unsigned) size);
- return;
+ g_warning ("%lu bytes requested for pixel buffer, this will slow down the system.", (long unsigned) size);
+ // do not quit here, let the system decide for RAM usage
+ // return;
}
pb->data.px = g_try_new (unsigned char, size);
if (pb->data.px == NULL) { // memory allocation failed
@@ -144,7 +152,7 @@ nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0,
w = x1 - x0;
bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
- pb->size = NR_PIXBLOCK_SIZE_STATIC;
+ pb->size = NR_PIXBLOCK_SIZE_STATIC;
pb->mode = mode;
pb->empty = empty;
pb->visible_area.x0 = pb->area.x0 = x0;
@@ -157,9 +165,9 @@ nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0,
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)
+ /// \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;
@@ -289,7 +297,7 @@ nr_pixelstore_4K_new (bool clear, unsigned char val)
} else {
px = g_new (unsigned char, 4096);
}
-
+
if (clear) memset (px, val, 4096);
return px;
@@ -323,7 +331,7 @@ nr_pixelstore_16K_new (bool clear, unsigned char val)
} else {
px = g_new (unsigned char, 16384);
}
-
+
if (clear) memset (px, val, 16384);
return px;