Code

Using the blur slider no longer destroys filters already applied to the object
authorkiirala <kiirala@users.sourceforge.net>
Sat, 23 Jun 2007 15:35:28 +0000 (15:35 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Sat, 23 Jun 2007 15:35:28 +0000 (15:35 +0000)
src/desktop-style.cpp
src/dialogs/object-properties.cpp
src/filter-chemistry.cpp
src/filter-chemistry.h
src/sp-feblend.cpp
src/sp-feoffset.cpp
src/sp-filter-primitive.cpp
src/sp-filter.cpp
src/sp-filter.h
src/sp-gaussian-blur.cpp

index 9c7cbb35ffc59bdd4b5fb788177b7daad8a9ab30..95abdfa5bc6c04d4316b2e288d5d9a44399697c7 100644 (file)
@@ -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; i<style->filter.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) {
index 4db82385afcaca5b140128d6e53ff90bffca1248..fbc9ab83fc432292aa2d5f39e87001ac64ef9e3c 100644 (file)
@@ -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
index 164a6594a71fe16c483f979921c2cd6be995603a..90a6e32f2ca4aede9b6bb2d7aa716ed8489f7f02 100644 (file)
@@ -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
  */
 #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<NR::Rect> 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++
index 22ae9aecd2c52cc53ab943d8e53344e0c16ecf64..b727536adaf645a81f34e4de513d9a619c748fd2 100644 (file)
@@ -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
 
index bedbf4f610710da3f9d29048693d1544997d40e6..1c560e81bdc96c31a3b37599d31ba183f3dad624 100644 (file)
@@ -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) {
index 298d3e495981cd25e8197d16b9d24d423dd3ceff..b4a50679ed18fcec7280c5df422c4ce3b35caca2 100644 (file)
@@ -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) {
index cd8c53c653b88255356fe30329a8e7b12e4a9766..e8b7593f0a9e5e5ecb57eaaacafcd67968219ad5 100644 (file)
@@ -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) {
index 2b1b94b1fa9c32782fe0b978c2501cb3ea39be29..11aa30e0bc37d8d2bc74b70cd10b38d1ffa2b1e2 100644 (file)
@@ -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) {
index 55e3eaa0ad5228a48ba78a7a38472bcda2d050e2..c6edc6c65caf8407033c91b8f86056e0aac619e5 100644 (file)
@@ -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<gchar *, int, ltstr> _image_name;
index bc65574ca6982dd9311b3294ce788e5755651e65..8b7578fe8f058b751e54715cb95c412725487624 100644 (file)
@@ -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");
     }