X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-filter.cpp;h=7197c1ec93539c53810f0d0db80ac58703a24882;hb=c635a682d950f1421ca59bdb63e2bf83db697ad3;hp=b45eb0122743d9be8e10c21535b9f61dce533604;hpb=6c1edd8c9f1d31e0b4ceafa26f44692e18ee09d2;p=inkscape.git diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index b45eb0122..7197c1ec9 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -6,8 +6,9 @@ /* * Authors: * Hugo Rodrigues + * Niko Kiirala * - * Copyright (C) 2006 Hugo Rodrigues + * Copyright (C) 2006,2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -16,57 +17,26 @@ # include "config.h" #endif +#include +#include +using std::map; +using std::pair; + +#include + #include "attributes.h" #include "document.h" #include "sp-filter.h" #include "sp-filter-reference.h" #include "uri.h" #include "xml/repr.h" +#include +#include #define SP_MACROS_SILENT #include "macros.h" -#define DEBUG_FILTER -#ifdef DEBUG_FILTER -# define debug(f, a...) { g_print("%s(%d) %s:", \ - __FILE__,__LINE__,__FUNCTION__); \ - g_print(f, ## a); \ - g_print("\n"); \ - } -#else -# define debug(f, a...) /**/ -#endif - - -/* - * For debugging purposes only - */ -void printfilter(SPFilter *filter) -{ - if(filter->filterUnits==SP_FILTER_UNITS_USERSPACEONUSE) - g_print("filterUnits=SP_FILTER_UNITS_USERSPACEONUSE\n"); - else if(filter->filterUnits==SP_FILTER_UNITS_OBJECTBOUNDINGBOX) - g_print("filterUnits=SP_FILTER_UNITS_OBJECTBOUNDINGBOX\n"); - else - g_print("filterUnits=UNKNOWN!!!\n"); - - if(filter->primitiveUnits==SP_FILTER_UNITS_USERSPACEONUSE) - g_print("primitiveUnits=SP_FILTER_UNITS_USERSPACEONUSE\n"); - else if(filter->primitiveUnits==SP_FILTER_UNITS_OBJECTBOUNDINGBOX) - g_print("primitiveUnits=SP_FILTER_UNITS_OBJECTBOUNDINGBOX\n"); - else - g_print("primitiveUnits=UNKNOWN!!!\n"); - -//TODO: print X, Y, W and H units - g_print("x=%lf\n", filter->x.computed); - g_print("y=%lf\n", filter->y.computed); - g_print("width=%lf\n", filter->width.computed); - g_print("height=%lf\n", filter->height.computed); - g_print("filterRes=(%lf %lf)\n", filter->filterRes.getNumber(), filter->filterRes.getOptNumber()); - -} - - +#include "display/nr-filter.h" /* Filter base class */ @@ -77,10 +47,14 @@ static void sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XM static void sp_filter_release(SPObject *object); static void sp_filter_set(SPObject *object, unsigned int key, gchar const *value); static void sp_filter_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); +static void sp_filter_child_added(SPObject *object, + Inkscape::XML::Node *child, + Inkscape::XML::Node *ref); +static void sp_filter_remove_child(SPObject *object, Inkscape::XML::Node *child); +static Inkscape::XML::Node *sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter); -static void filter_ref_modified(SPObject *href, SPFilter *filter); +static void filter_ref_modified(SPObject *href, guint flags, SPFilter *filter); static SPObjectClass *filter_parent_class; @@ -118,6 +92,8 @@ sp_filter_class_init(SPFilterClass *klass) sp_object_class->write = sp_filter_write; sp_object_class->set = sp_filter_set; sp_object_class->update = sp_filter_update; + sp_object_class->child_added = sp_filter_child_added; + sp_object_class->remove_child = sp_filter_remove_child; } static void @@ -136,6 +112,15 @@ sp_filter_init(SPFilter *filter) filter->filterUnits_set = FALSE; filter->primitiveUnits_set = FALSE; + filter->_renderer = NULL; + + filter->_image_name = new std::map; + filter->_image_name->clear(); + filter->_image_number_next = 0; + + filter->filterRes = NumberOptNumber(); + + new (&filter->modified_connection) sigc::connection(); } /** @@ -146,7 +131,6 @@ sp_filter_init(SPFilter *filter) static void sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { - debug("0x%p",object); if (((SPObjectClass *) filter_parent_class)->build) { ((SPObjectClass *) filter_parent_class)->build(object, document, repr); } @@ -171,7 +155,6 @@ sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep static void sp_filter_release(SPObject *object) { - debug("0x%p",object); SPFilter *filter = SP_FILTER(object); if (SP_OBJECT_DOCUMENT(object)) { @@ -183,14 +166,15 @@ sp_filter_release(SPObject *object) //release href if (filter->href) { - if (filter->href->getObject()) { - sp_signal_disconnect_by_data(filter->href->getObject(), filter); - } + filter->modified_connection.disconnect(); filter->href->detach(); delete filter->href; filter->href = NULL; } + filter->modified_connection.~connection(); + delete filter->_image_name; + if (((SPObjectClass *) filter_parent_class)->release) ((SPObjectClass *) filter_parent_class)->release(object); } @@ -201,8 +185,6 @@ sp_filter_release(SPObject *object) static void sp_filter_set(SPObject *object, unsigned int key, gchar const *value) { - debug("0x%p %s(%u): '%s'",object, - sp_attribute_name(key),key,value); SPFilter *filter = SP_FILTER(object); switch (key) { @@ -234,24 +216,25 @@ sp_filter_set(SPObject *object, unsigned int key, gchar const *value) } object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_X: + case SP_ATTR_X: filter->x.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_Y: - filter->y.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + case SP_ATTR_Y: + filter->y.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_WIDTH: - filter->width.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + case SP_ATTR_WIDTH: + filter->width.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_HEIGHT: - filter->height.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + case SP_ATTR_HEIGHT: + filter->height.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_FILTERRES: - filter->filterRes.set(value); + case SP_ATTR_FILTERRES: + filter->filterRes.set(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_XLINK_HREF: if (value) { @@ -266,7 +249,7 @@ sp_filter_set(SPObject *object, unsigned int key, gchar const *value) } break; default: - /* See if any parents need this value. */ + // See if any parents need this value. if (((SPObjectClass *) filter_parent_class)->set) { ((SPObjectClass *) filter_parent_class)->set(object, key, value); } @@ -280,7 +263,6 @@ sp_filter_set(SPObject *object, unsigned int key, gchar const *value) static void sp_filter_update(SPObject *object, SPCtx *ctx, guint flags) { - debug("0x%p",object); //SPFilter *filter = SP_FILTER(object); if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | @@ -299,13 +281,32 @@ sp_filter_update(SPObject *object, SPCtx *ctx, guint flags) * Writes its settings to an incoming repr object, if any. */ static Inkscape::XML::Node * -sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) +sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { - debug("0x%p",object); SPFilter *filter = SP_FILTER(object); - - if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(); + SPObject *child; + Inkscape::XML::Node *crepr; + + /* Original from sp-item-group.cpp */ + if (flags & SP_OBJECT_WRITE_BUILD) { + GSList *l; + if (!repr) { + repr = doc->createElement("svg:filter"); + } + l = NULL; + for (child = sp_object_first_child(object); child != NULL; child = SP_OBJECT_NEXT(child) ) { + crepr = child->updateRepr(doc, NULL, flags); + if (crepr) l = g_slist_prepend (l, crepr); + } + while (l) { + repr->addChild((Inkscape::XML::Node *) l->data, NULL); + Inkscape::GC::release((Inkscape::XML::Node *) l->data); + l = g_slist_remove (l, l->data); + } + } else { + for (child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + child->updateRepr(flags); + } } if ((flags & SP_OBJECT_WRITE_ALL) || filter->filterUnits_set) { @@ -354,9 +355,10 @@ sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) repr->setAttribute("height", NULL); } - if (filter->filterRes._set) { - char filterRes[32]; - repr->setAttribute("filterRes", filter->filterRes.getValueString(filterRes)); + if (filter->filterRes.getNumber()>=0) { + gchar *tmp = filter->filterRes.getValueString(); + repr->setAttribute("filterRes", tmp); + g_free(tmp); } else { repr->setAttribute("filterRes", NULL); } @@ -367,8 +369,17 @@ sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) g_free(uri_string); } + // TODO: This is evil, correctly implement support for color-interpolation-filters!!! + // The color-interpolation-filters attribute is initially set to linearRGB according to the SVG standard. + // However, Inkscape completely ignores it and implicitly assumes that it is sRGB (like color-interpolation-filters). + // This results in a discrepancy between Inkscape and other renderers in how they render filters. + // To mitigate this problem I've (Jasper van de Gronde,th.v.d.gronde@hccnet.nl) added this to ensure that at least + // any filters written by Inkscape will henceforth be rendered the same in other renderers. + // In the future Inkscape should have proper support for the color-interpolation properties and this should be changed. + repr->setAttribute("color-interpolation-filters", "sRGB"); + if (((SPObjectClass *) filter_parent_class)->write) { - ((SPObjectClass *) filter_parent_class)->write(object, repr, flags); + ((SPObjectClass *) filter_parent_class)->write(object, doc, repr, flags); } return repr; @@ -382,23 +393,184 @@ static void filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter) { if (old_ref) { - sp_signal_disconnect_by_data(old_ref, filter); + filter->modified_connection.disconnect(); } if ( SP_IS_FILTER(ref) && ref != filter ) { - g_signal_connect(G_OBJECT(ref), "modified", G_CALLBACK(filter_ref_modified), filter); + filter->modified_connection = + ref->connectModified(sigc::bind(sigc::ptr_fun(&filter_ref_modified), filter)); } - filter_ref_modified(ref, filter); + filter_ref_modified(ref, 0, filter); } static void -filter_ref_modified(SPObject *href, SPFilter *filter) +filter_ref_modified(SPObject */*href*/, guint /*flags*/, SPFilter *filter) { SP_OBJECT(filter)->requestModified(SP_OBJECT_MODIFIED_FLAG); } +/** + * Callback for child_added event. + */ +static void +sp_filter_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) +{ + //SPFilter *f = SP_FILTER(object); + + if (((SPObjectClass *) filter_parent_class)->child_added) + (* ((SPObjectClass *) filter_parent_class)->child_added)(object, child, ref); + + object->requestModified(SP_OBJECT_MODIFIED_FLAG); +} + +/** + * Callback for remove_child event. + */ +static void +sp_filter_remove_child(SPObject *object, Inkscape::XML::Node *child) +{ +// SPFilter *f = SP_FILTER(object); + + if (((SPObjectClass *) filter_parent_class)->remove_child) + (* ((SPObjectClass *) filter_parent_class)->remove_child)(object, child); + + object->requestModified(SP_OBJECT_MODIFIED_FLAG); +} + +void sp_filter_build_renderer(SPFilter *sp_filter, Inkscape::Filters::Filter *nr_filter) +{ + g_assert(sp_filter != NULL); + g_assert(nr_filter != NULL); + + sp_filter->_renderer = nr_filter; + + nr_filter->set_x(sp_filter->x); + nr_filter->set_y(sp_filter->y); + nr_filter->set_width(sp_filter->width); + nr_filter->set_height(sp_filter->height); + + if (sp_filter->filterRes.getNumber() >= 0) { + if (sp_filter->filterRes.getOptNumber() >= 0) { + nr_filter->set_resolution(sp_filter->filterRes.getNumber(), + sp_filter->filterRes.getOptNumber()); + } else { + nr_filter->set_resolution(sp_filter->filterRes.getNumber()); + } + } + + nr_filter->clear_primitives(); + SPObject *primitive_obj = sp_filter->children; + while (primitive_obj) { + if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { + SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj); + g_assert(primitive != NULL); + if (((SPFilterPrimitiveClass*) G_OBJECT_GET_CLASS(primitive))->build_renderer) { + ((SPFilterPrimitiveClass *) G_OBJECT_GET_CLASS(primitive))->build_renderer(primitive, nr_filter); + } else { + g_warning("Cannot build filter renderer: missing builder"); + } + } + primitive_obj = primitive_obj->next; + } +} + +int sp_filter_primitive_count(SPFilter *filter) { + g_assert(filter != NULL); + int count = 0; + + SPObject *primitive_obj = filter->children; + while (primitive_obj) { + if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) count++; + primitive_obj = primitive_obj->next; + } + return count; +} + +int sp_filter_get_image_name(SPFilter *filter, gchar const *name) { + gchar *name_copy = strdup(name); + map::iterator result = filter->_image_name->find(name_copy); + free(name_copy); + if (result == filter->_image_name->end()) return -1; + else return (*result).second; +} + +int sp_filter_set_image_name(SPFilter *filter, gchar const *name) { + int value = filter->_image_number_next; + filter->_image_number_next++; + gchar *name_copy = strdup(name); + pair new_pair(name_copy, value); + pair::iterator,bool> ret = filter->_image_name->insert(new_pair); + if (ret.second == false) { + return (*ret.first).second; + } + return value; +} + +gchar const *sp_filter_name_for_image(SPFilter const *filter, int const image) { + switch (image) { + case Inkscape::Filters::NR_FILTER_SOURCEGRAPHIC: + return "SourceGraphic"; + break; + case Inkscape::Filters::NR_FILTER_SOURCEALPHA: + return "SourceAlpha"; + break; + case Inkscape::Filters::NR_FILTER_BACKGROUNDIMAGE: + return "BackgroundImage"; + break; + case Inkscape::Filters::NR_FILTER_BACKGROUNDALPHA: + return "BackgroundAlpha"; + break; + case Inkscape::Filters::NR_FILTER_STROKEPAINT: + return "StrokePaint"; + break; + case Inkscape::Filters::NR_FILTER_FILLPAINT: + return "FillPaint"; + break; + case Inkscape::Filters::NR_FILTER_SLOT_NOT_SET: + case Inkscape::Filters::NR_FILTER_UNNAMED_SLOT: + return 0; + break; + default: + for (map::const_iterator i + = filter->_image_name->begin() ; + i != filter->_image_name->end() ; i++) { + if (i->second == image) { + return i->first; + } + } + } + return 0; +} + +Glib::ustring sp_filter_get_new_result_name(SPFilter *filter) { + g_assert(filter != NULL); + int largest = 0; + + SPObject *primitive_obj = filter->children; + while (primitive_obj) { + if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { + Inkscape::XML::Node *repr = SP_OBJECT_REPR(primitive_obj); + char const *result = repr->attribute("result"); + int index; + if (result && sscanf(result, "result%d", &index) == 1) { + if (index > largest) { + largest = index; + } + } + } + primitive_obj = primitive_obj->next; + } + + return "result" + Glib::Ascii::dtostr(largest + 1); +} + +bool ltstr::operator()(const char* s1, const char* s2) const +{ + return strcmp(s1, s2) < 0; +} + /* Local Variables: