From 368622010cf5cb2dda801c6a3ad939e28757a635 Mon Sep 17 00:00:00 2001 From: kiirala Date: Sat, 23 Jun 2007 15:35:28 +0000 Subject: [PATCH] Using the blur slider no longer destroys filters already applied to the object --- src/desktop-style.cpp | 31 ++--- src/dialogs/object-properties.cpp | 4 +- src/filter-chemistry.cpp | 183 +++++++++++++++++++++++++++--- src/filter-chemistry.h | 5 +- src/sp-feblend.cpp | 3 +- src/sp-feoffset.cpp | 8 +- src/sp-filter-primitive.cpp | 10 +- src/sp-filter.cpp | 69 ++++------- src/sp-filter.h | 3 - src/sp-gaussian-blur.cpp | 2 +- 10 files changed, 224 insertions(+), 94 deletions(-) diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 9c7cbb35f..95abdfa5b 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1040,23 +1040,26 @@ objects_query_blur (GSList *objects, SPStyle *style_res) //if object has a filter if (style->filter.set && style->filter.filter) { //cycle through filter primitives - for(int i=0; ifilter.filter->_primitive_count; i++) - { - SPFilterPrimitive *primitive = style->filter.filter->_primitives[i]; - //if primitive is gaussianblur - if(SP_IS_GAUSSIANBLUR(primitive)) { - SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive); - float num = spblur->stdDeviation.getNumber(); - blur_sum += num * NR::expansion(i2d); - if (blur_prev != -1 && fabs (num - blur_prev) > 1e-2) // rather low tolerance because difference in blur radii is much harder to notice than e.g. difference in sizes - same_blur = false; - blur_prev = num; - //TODO: deal with opt number, for the moment it's not necessary to the ui. - blur_items ++; + SPObject *primitive_obj = style->filter.filter->children; + while (primitive_obj) { + if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { + SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj); + + //if primitive is gaussianblur + if(SP_IS_GAUSSIANBLUR(primitive)) { + SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive); + float num = spblur->stdDeviation.getNumber(); + blur_sum += num * NR::expansion(i2d); + if (blur_prev != -1 && fabs (num - blur_prev) > 1e-2) // rather low tolerance because difference in blur radii is much harder to notice than e.g. difference in sizes + same_blur = false; + blur_prev = num; + //TODO: deal with opt number, for the moment it's not necessary to the ui. + blur_items ++; + } } + primitive_obj = primitive_obj->next; } } - } if (items > 0) { diff --git a/src/dialogs/object-properties.cpp b/src/dialogs/object-properties.cpp index 4db82385a..fbc9ab83f 100644 --- a/src/dialogs/object-properties.cpp +++ b/src/dialogs/object-properties.cpp @@ -434,9 +434,9 @@ sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *base) g_assert(style != NULL); if (radius == 0.0) { - remove_filter (item, false); + remove_filter_gaussian_blur(item); } else { - SPFilter *constructed = new_filter_gaussian_blur_from_item(document, item, radius); + SPFilter *constructed = modify_filter_gaussian_blur_from_item(document, item, radius); sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false); } //request update diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index 164a6594a..90a6e32f2 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -6,8 +6,9 @@ * Authors: * Hugo Rodrigues * bulia byak + * Niko Kiirala * - * Copyright (C) 2006 authors + * Copyright (C) 2006,2007 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -24,24 +25,46 @@ #include "xml/repr.h" /** - * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height + * Count how many times the filter is used by the styles of o and its + * descendants */ -SPFilter * -new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion, double expansionX, double expansionY, double width, double height) +static guint +count_filter_hrefs(SPObject *o, SPFilter *filter) { - g_return_val_if_fail(document != NULL, NULL); + if (!o) + return 1; - SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + guint i = 0; - Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + SPStyle *style = SP_OBJECT_STYLE(o); + if (style + && style->filter.set + && style->filter.filter == filter) + { + i ++; + } - // create a new filter - Inkscape::XML::Node *repr; - repr = xml_doc->createElement("svg:filter"); - repr->setAttribute("inkscape:collect", "always"); + for (SPObject *child = sp_object_first_child(o); + child != NULL; child = SP_OBJECT_NEXT(child)) { + i += count_filter_hrefs(child, filter); + } - double rx = radius * (expansionY != 0? (expansion / expansionY) : 1); - double ry = radius * (expansionX != 0? (expansion / expansionX) : 1); + return i; +} + +/** + * Sets a suitable filter effects area according to given blur radius, + * expansion and object size. + */ +static void set_filter_area(Inkscape::XML::Node *repr, gdouble radius, + double expansion, double expansionX, + double expansionY, double width, double height) +{ + // TODO: make this more generic, now assumed, that only the blur + // being added can affect the required filter area + + double rx = radius * (expansionY != 0 ? (expansion / expansionY) : 1); + double ry = radius * (expansionX != 0 ? (expansion / expansionX) : 1); if (width != 0 && height != 0 && (2.4 * rx > width * 0.1 || 2.4 * ry > height * 0.1)) { // If not within the default 10% margin (see @@ -57,11 +80,32 @@ new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion sp_repr_set_svg_double(repr, "y", -ymargin); sp_repr_set_svg_double(repr, "height", 1 + 2 * ymargin); } +} + +/** + * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height + */ +SPFilter * +new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion, double expansionX, double expansionY, double width, double height) +{ + g_return_val_if_fail(document != NULL, NULL); + + SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // create a new filter + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:filter"); + //repr->setAttribute("inkscape:collect", "always"); + + set_filter_area(repr, radius, expansion, expansionX, expansionY, + width, height); //create feGaussianBlur node Inkscape::XML::Node *b_repr; b_repr = xml_doc->createElement("svg:feGaussianBlur"); - b_repr->setAttribute("inkscape:collect", "always"); + //b_repr->setAttribute("inkscape:collect", "always"); double stdDeviation = radius; if (expansion != 0) @@ -112,6 +156,89 @@ new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble return (new_filter_gaussian_blur (document, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height)); } +/** + * Modifies the gaussian blur applied to the item. + * If no filters are applied to given item, creates a new blur filter. + * If a filter is applied and it contains a blur, modify that blur. + * If the filter doesn't contain blur, a blur is added to the filter. + * Should there be more references to modified filter, that filter is + * duplicated, so that other elements referring that filter are not modified. + */ +/* TODO: this should be made more generic, not just for blurs */ +SPFilter * +modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *item, + gdouble radius) +{ + if (!item->style || !item->style->filter.set) { + return new_filter_gaussian_blur_from_item(document, item, radius); + } + + SPFilter *filter = SP_FILTER(item->style->filter.filter); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // If there are more users for this filter, duplicate it + if (SP_OBJECT_HREFCOUNT(filter) > count_filter_hrefs(item, filter)) { + Inkscape::XML::Node *repr; + repr = SP_OBJECT_REPR(item)->duplicate(xml_doc); + SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + SP_OBJECT_REPR(defs)->appendChild(repr); + + filter = SP_FILTER( document->getObjectByRepr(repr) ); + Inkscape::GC::release(repr); + } + + // Determine the required standard deviation value + NR::Matrix i2d = sp_item_i2d_affine (item); + double expansion = i2d.expansion(); + double stdDeviation = radius; + if (expansion != 0) + stdDeviation /= expansion; + + // Get the object size + NR::Maybe const r = sp_item_bbox_desktop(item); + double width; + double height; + if (r) { + width = r->extent(NR::X); + height= r->extent(NR::Y); + } else { + width = height = 0; + } + + // Set the filter effects area + Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->filter.filter); + set_filter_area(repr, radius, expansion, i2d.expansionX(), + i2d.expansionY(), width, height); + + // Search for gaussian blur primitives. If found, set the stdDeviation + // of the first one and return. + Inkscape::XML::Node *primitive = repr->firstChild(); + while (primitive) { + if (strcmp("svg:feGaussianBlur", primitive->name()) == 0) { + sp_repr_set_svg_double(primitive, "stdDeviation", + stdDeviation); + return filter; + } + primitive = primitive->next(); + } + + // If there were no gaussian blur primitives, create a new one + + //create feGaussianBlur node + Inkscape::XML::Node *b_repr; + b_repr = xml_doc->createElement("svg:feGaussianBlur"); + //b_repr->setAttribute("inkscape:collect", "always"); + + //set stdDeviation attribute + sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation); + + //set feGaussianBlur as child of filter node + SP_OBJECT_REPR(filter)->appendChild(b_repr); + Inkscape::GC::release(b_repr); + + return filter; +} + void remove_filter (SPObject *item, bool recursive) { SPCSSAttr *css = sp_repr_css_attr_new (); @@ -123,6 +250,34 @@ void remove_filter (SPObject *item, bool recursive) sp_repr_css_attr_unref (css); } +/** + * Removes the first feGaussianBlur from the filter attached to given item. + * Should this leave us with an empty filter, remove that filter. + */ +/* TODO: the removed filter primitive may had had a named result image, so + * after removing, the filter may be in erroneous state, this situation should + * be handled gracefully */ +void remove_filter_gaussian_blur (SPObject *item) +{ + if (item->style && item->style->filter.set && item->style->filter.filter) { + // Search for the first blur primitive and remove it. (if found) + Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->filter.filter); + Inkscape::XML::Node *primitive = repr->firstChild(); + while (primitive) { + if (strcmp("svg:feGaussianBlur", primitive->name()) == 0) { + sp_repr_unparent(primitive); + break; + } + primitive = primitive->next(); + } + + // If there are no more primitives left in this filter, discard it. + if (repr->childCount() == 0) { + remove_filter(item, false); + } + } +} + /* Local Variables: mode:c++ diff --git a/src/filter-chemistry.h b/src/filter-chemistry.h index 22ae9aecd..b727536ad 100644 --- a/src/filter-chemistry.h +++ b/src/filter-chemistry.h @@ -7,8 +7,9 @@ * Authors: * Hugo Rodrigues * bulia byak + * Niko Kiirala * - * Copyright (C) 2006 authors + * Copyright (C) 2006,2007 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -18,7 +19,9 @@ SPFilter *new_filter_gaussian_blur (SPDocument *document, gdouble stdDeviation, double expansion, double expansionX, double expansionY, double width, double height); SPFilter *new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation); +SPFilter *modify_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation); void remove_filter (SPObject *item, bool recursive); +void remove_filter_gaussian_blur (SPObject *item); #endif diff --git a/src/sp-feblend.cpp b/src/sp-feblend.cpp index bedbf4f61..1c560e81b 100644 --- a/src/sp-feblend.cpp +++ b/src/sp-feblend.cpp @@ -187,8 +187,9 @@ sp_feBlend_set(SPObject *object, unsigned int key, gchar const *value) static void sp_feBlend_update(SPObject *object, SPCtx *ctx, guint flags) { - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) { + if (flags & SP_OBJECT_MODIFIED_FLAG) { sp_object_read_attr(object, "mode"); + sp_object_read_attr(object, "in2"); } if (((SPObjectClass *) feBlend_parent_class)->update) { diff --git a/src/sp-feoffset.cpp b/src/sp-feoffset.cpp index 298d3e495..b4a50679e 100644 --- a/src/sp-feoffset.cpp +++ b/src/sp-feoffset.cpp @@ -154,11 +154,9 @@ sp_feOffset_set(SPObject *object, unsigned int key, gchar const *value) static void sp_feOffset_update(SPObject *object, SPCtx *ctx, guint flags) { - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | - SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - - /* do something to trigger redisplay, updates? */ - + if (flags & SP_OBJECT_MODIFIED_FLAG) { + sp_object_read_attr(object, "dx"); + sp_object_read_attr(object, "dy"); } if (((SPObjectClass *) feOffset_parent_class)->update) { diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp index cd8c53c65..e8b7593f0 100644 --- a/src/sp-filter-primitive.cpp +++ b/src/sp-filter-primitive.cpp @@ -99,9 +99,6 @@ sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML: sp_object_read_attr(object, "in"); sp_object_read_attr(object, "result"); - - if (object->parent) - add_primitive((SPFilter*)object->parent, (SPFilterPrimitive*)object); } /** @@ -164,10 +161,9 @@ sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags) { //SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object); - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | - SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - - /* do something to trigger redisplay, updates? */ + if (flags & SP_OBJECT_MODIFIED_FLAG) { + sp_object_read_attr(object, "in"); + sp_object_read_attr(object, "result"); } if (((SPObjectClass *) filter_primitive_parent_class)->update) { diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index 2b1b94b1f..11aa30e0b 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -107,11 +107,6 @@ sp_filter_init(SPFilter *filter) filter->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; filter->filterUnits_set = FALSE; filter->primitiveUnits_set = FALSE; - filter->_primitive_count=0; - - filter->_primitive_table_size = 1; - filter->_primitives = new SPFilterPrimitive*[1]; - filter->_primitives[0] = NULL; filter->_renderer = NULL; @@ -375,43 +370,18 @@ filter_ref_modified(SPObject *href, guint flags, SPFilter *filter) SP_OBJECT(filter)->requestModified(SP_OBJECT_MODIFIED_FLAG); } - -void _enlarge_primitive_table(SPFilter * filter) { - SPFilterPrimitive **new_tbl = new SPFilterPrimitive*[filter->_primitive_table_size * 2]; - for (int i = 0 ; i < filter->_primitive_count ; i++) { - new_tbl[i] = filter->_primitives[i]; - } - filter->_primitive_table_size *= 2; - for (int i = filter->_primitive_count ; i < filter->_primitive_table_size ; i++) { - new_tbl[i] = NULL; - } - delete[] filter->_primitives; - filter->_primitives = new_tbl; -} - -SPFilterPrimitive *add_primitive(SPFilter *filter, SPFilterPrimitive *primitive) -{ - if (filter->_primitive_count >= filter->_primitive_table_size) { - _enlarge_primitive_table(filter); - } - filter->_primitives[filter->_primitive_count] = primitive; - filter->_primitive_count++; - return primitive; -} - /** * 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); +{ + //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); - */ } /** @@ -419,17 +389,13 @@ sp_filter_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XM */ static void sp_filter_remove_child(SPObject *object, Inkscape::XML::Node *child) -{/* - SPFilter *f = SP_FILTER(object); +{ +// SPFilter *f = SP_FILTER(object); if (((SPObjectClass *) filter_parent_class)->remove_child) (* ((SPObjectClass *) filter_parent_class)->remove_child)(object, child); - SPObject *ochild; - - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - */ } void sp_filter_build_renderer(SPFilter *sp_filter, NR::Filter *nr_filter) @@ -445,20 +411,31 @@ void sp_filter_build_renderer(SPFilter *sp_filter, NR::Filter *nr_filter) nr_filter->set_height(sp_filter->height); nr_filter->clear_primitives(); - for (int i = 0 ; i < sp_filter->_primitive_count ; i++) { - SPFilterPrimitive *primitive = sp_filter->_primitives[i]; - 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"); + 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); - return filter->_primitive_count; + 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) { diff --git a/src/sp-filter.h b/src/sp-filter.h index 55e3eaa0a..c6edc6c65 100644 --- a/src/sp-filter.h +++ b/src/sp-filter.h @@ -57,9 +57,6 @@ struct SPFilter : public SPObject { /** HREF attribute */ SPFilterReference *href; - int _primitive_count; - int _primitive_table_size; - SPFilterPrimitive ** _primitives; NR::Filter *_renderer; std::map _image_name; diff --git a/src/sp-gaussian-blur.cpp b/src/sp-gaussian-blur.cpp index bc65574ca..8b7578fe8 100644 --- a/src/sp-gaussian-blur.cpp +++ b/src/sp-gaussian-blur.cpp @@ -142,7 +142,7 @@ sp_gaussianBlur_set(SPObject *object, unsigned int key, gchar const *value) static void sp_gaussianBlur_update(SPObject *object, SPCtx *ctx, guint flags) { - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) { + if (flags & SP_OBJECT_MODIFIED_FLAG) { sp_object_read_attr(object, "stdDeviation"); } -- 2.30.2