From e599136b2d83b35f3aebf9487f8ea9989c077bb4 Mon Sep 17 00:00:00 2001 From: jucablues Date: Mon, 25 Feb 2008 05:09:02 +0000 Subject: [PATCH] svg element referenced by id part of feImage filter rendering. This commit introduces some known bugs. I will fill a bug report about it, so that we don't forget it. Nominally they are: * seems to leak memory. I haven't found out how. Needs review. * it works when you create and use the filter, but it crashes when trying to open a file that already contains a filter using feImage referencing an svgelement. --- src/display/nr-filter-image.cpp | 78 +++++++++++++++++++++++-- src/display/nr-filter-image.h | 4 ++ src/sp-feimage.cpp | 34 +++++++++-- src/sp-feimage.h | 3 + src/ui/dialog/filter-effects-dialog.cpp | 2 +- 5 files changed, 112 insertions(+), 9 deletions(-) diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 78e5ef8ec..42b78fa16 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -10,10 +10,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ #include "document.h" +#include "sp-item.h" +#include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" #include "display/nr-filter-units.h" +#include "libnr/nr-matrix.h" +#include "libnr/nr-rect-l.h" namespace NR { @@ -36,6 +40,64 @@ FilterImage::~FilterImage() int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { if (!feImageHref) return 0; + NRPixBlock* pb; + bool free_pb_on_exit = false; + + if(from_element){ + if (!SVGElem) return 0; + + // prep the document + sp_document_ensure_up_to_date(document); + NRArena* arena = NRArena::create(); + unsigned const key = sp_item_display_key_new(1); + NRArenaItem* ai = sp_item_invoke_show(SVGElem, arena, key, SP_ITEM_SHOW_DISPLAY); + if (!ai) { + g_warning("feImage renderer: error creating NRArenaItem for SVG Element"); + g_free(arena); + return 0; + } + pb = new NRPixBlock; + free_pb_on_exit = true; + + Matrix identity(1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0); + NR::Maybe area = SVGElem->getBounds(identity); + + NRRectL rect; + rect.x0=area->min()[NR::X]; + rect.x1=area->max()[NR::X]; + rect.y0=area->min()[NR::Y]; + rect.y1=area->max()[NR::Y]; + + width = (int)(rect.x1-rect.x0); + height = (int)(rect.y1-rect.y0); + + if (image_pixbuf) g_free(image_pixbuf); + image_pixbuf = g_new(unsigned char, 4 * width * height); + memset(image_pixbuf, 0x00, 4 * width * height); + + NRGC gc(NULL); + /* Update to renderable state */ + double sf = 1.0; + NRMatrix t; + nr_matrix_set_scale(&t, sf, sf); + nr_arena_item_set_transform(ai, &t); + nr_matrix_set_identity(&gc.transform); + nr_arena_item_invoke_update( ai, NULL, &gc, + NR_ARENA_ITEM_STATE_ALL, + NR_ARENA_ITEM_STATE_NONE ); + nr_pixblock_setup_extern(pb, NR_PIXBLOCK_MODE_R8G8B8A8N, + (int)rect.x0, (int)rect.y0, (int)rect.x1, (int)rect.y1, + image_pixbuf, 4 * width, FALSE, FALSE ); + + nr_arena_item_invoke_render(NULL, ai, &rect, pb, NR_ARENA_ITEM_RENDER_NO_CACHE); + + nr_arena_item_unref(ai); + nr_object_unref((NRObject *) arena); + } + + if (!image_pixbuf){ try { gchar *fullname = feImageHref; @@ -116,13 +178,21 @@ int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { coordx = ( indexX >= 0 ? int( indexX ) : -1 ); coordy = ( indexY >= 0 ? int( indexY ) : -1 ); if (coordx >= 0 && coordx < width && coordy >= 0 && coordy < height){ - out_data[4*((x - x0)+w*(y - y0))] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy]; //Red - out_data[4*((x - x0)+w*(y - y0)) + 1] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 1]; //Green - out_data[4*((x - x0)+w*(y - y0)) + 2] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 2]; //Blue - out_data[4*((x - x0)+w*(y - y0)) + 3] = 255; //Alpha + if (from_element){ + out_data[4*((x - x0)+w*(y - y0))] = (unsigned char) image_pixbuf[4*(coordx + width*coordy)]; //Red + out_data[4*((x - x0)+w*(y - y0)) + 1] = (unsigned char) image_pixbuf[4*(coordx + width*coordy) + 1]; //Green + out_data[4*((x - x0)+w*(y - y0)) + 2] = (unsigned char) image_pixbuf[4*(coordx + width*coordy) + 2]; //Blue + out_data[4*((x - x0)+w*(y - y0)) + 3] = (unsigned char) image_pixbuf[4*(coordx + width*coordy) + 3]; //Alpha + } else { + out_data[4*((x - x0)+w*(y - y0))] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy]; //Red + out_data[4*((x - x0)+w*(y - y0)) + 1] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 1]; //Green + out_data[4*((x - x0)+w*(y - y0)) + 2] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 2]; //Blue + out_data[4*((x - x0)+w*(y - y0)) + 3] = 255; //Alpha + } } } } + if (free_pb_on_exit) nr_pixblock_release(pb); out->empty = FALSE; slot.set(_output, out); diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index afa9f798c..42e7f089a 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -16,6 +16,7 @@ #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" #include +#include "sp-item.h" namespace NR { @@ -30,6 +31,9 @@ public: void set_document( SPDocument *document ); void set_href(const gchar *href); void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height); + bool from_element; + SPItem* SVGElem; + private: SPDocument *document; gchar *feImageHref; diff --git a/src/sp-feimage.cpp b/src/sp-feimage.cpp index 271baa591..d72435f2c 100644 --- a/src/sp-feimage.cpp +++ b/src/sp-feimage.cpp @@ -18,7 +18,8 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif - +#include "uri.h" +#include "uri-references.h" #include "attributes.h" #include "svg/svg.h" #include "sp-feimage.h" @@ -130,14 +131,36 @@ sp_feImage_set(SPObject *object, unsigned int key, gchar const *value) { SPFeImage *feImage = SP_FEIMAGE(object); (void)feImage; - + Inkscape::URI* SVGElem_uri; + Inkscape::URIReference* SVGElemRef; switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_XLINK_HREF: if (feImage->href) g_free(feImage->href); feImage->href = (value) ? g_strdup (value) : NULL; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; + if (!feImage->href) return; + try{ + SVGElem_uri = new Inkscape::URI(feImage->href); + SVGElemRef = new Inkscape::URIReference(feImage->document); + feImage->from_element = true; + SVGElemRef->attach(*SVGElem_uri); + feImage->SVGElem = SP_ITEM(SVGElemRef->getObject()); + + g_free(SVGElem_uri); + g_free(SVGElemRef); + //TODO: maybe keeping SVGElemRef we can observe changes to the + // referenced object and trigger updates of the filtered object + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + } + catch(const Inkscape::UnsupportedURIException & e) + { + feImage->from_element = false; + g_warning("caught Inkscape::UnsupportedURIException in sp_feImage_set"); + break; + } + + case SP_ATTR_X: feImage->x.readOrUnset(value); object->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -215,6 +238,9 @@ static void sp_feImage_build_renderer(SPFilterPrimitive *primitive, NR::Filter * g_assert(nr_image != NULL); sp_filter_primitive_renderer_common(primitive, nr_primitive); + + nr_image->from_element = sp_image->from_element; + nr_image->SVGElem = sp_image->SVGElem; nr_image->set_region(sp_image->x, sp_image->y, sp_image->width, sp_image->height); nr_image->set_href(sp_image->href); nr_image->set_document(sp_image->document); diff --git a/src/sp-feimage.h b/src/sp-feimage.h index cf80a3166..d66a4fb77 100644 --- a/src/sp-feimage.h +++ b/src/sp-feimage.h @@ -17,6 +17,7 @@ #include "sp-filter.h" #include "sp-feimage-fns.h" #include "svg/svg-length.h" +#include "sp-item.h" /* FeImage base class */ class SPFeImageClass; @@ -26,6 +27,8 @@ struct SPFeImage : public SPFilterPrimitive { gchar *href; SVGLength x, y, height, width; SPDocument *document; + bool from_element; + SPItem* SVGElem; }; struct SPFeImageClass { diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 3a5c28520..6e9eeedb6 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -609,7 +609,7 @@ public: { pack_start(_entry, false, false); pack_start(_fromFile, false, false); - //pack_start(_fromSVGElement, false, false); + pack_start(_fromSVGElement, false, false); _fromFile.set_label(_("Image File")); _fromFile.signal_clicked().connect(sigc::mem_fun(*this, &FileOrElementChooser::select_file)); -- 2.39.5