Code

Filter effects dialog:
[inkscape.git] / src / desktop-style.cpp
index afb3a104528f62dff82213ee53114ba488f13771..a6a4d8567518399c31f87e2c39d42e9d67ed4792 100644 (file)
 #include "svg/svg.h"
 #include "svg/svg-color.h"
 #include "selection.h"
-#include "sp-tspan.h"
-#include "sp-textpath.h"
 #include "inkscape.h"
 #include "style.h"
 #include "prefs-utils.h"
 #include "sp-use.h"
+#include "sp-feblend.h"
+#include "sp-filter.h"
+#include "sp-filter-reference.h"
+#include "sp-gaussian-blur.h"
 #include "sp-flowtext.h"
 #include "sp-flowregion.h"
 #include "sp-flowdiv.h"
 #include "sp-linear-gradient.h"
-#include "sp-radial-gradient.h"
 #include "sp-pattern.h"
+#include "sp-radial-gradient.h"
+#include "sp-textpath.h"
+#include "sp-tref.h"
+#include "sp-tspan.h"
 #include "xml/repr.h"
 #include "libnrtype/font-style-to-pos.h"
 
-
 #include "desktop-style.h"
 
 /**
@@ -222,24 +226,59 @@ sp_desktop_get_color(SPDesktop *desktop, bool is_fill)
 }
 
 double
-sp_desktop_get_opacity_tool(SPDesktop *desktop, char const *tool, bool op)
+sp_desktop_get_master_opacity_tool(SPDesktop *desktop, char const *tool)
 {
     SPCSSAttr *css = NULL;
     gfloat value = 1.0; // default if nothing else found
     if (prefs_get_double_attribute(tool, "usecurrent", 0) != 0) {
-        css = sp_desktop_get_style(desktop, op);
+        css = sp_desktop_get_style(desktop, true);
     } else { 
         Inkscape::XML::Node *tool_repr = inkscape_get_repr(INKSCAPE, tool);
-        css = sp_repr_css_attr_inherited(tool_repr, "style");
+        if (tool_repr) {
+            css = sp_repr_css_attr_inherited(tool_repr, "style");
+        }
     }
    
-    gchar const *property = css ? sp_repr_css_property(css, "opacity", "1.000") : 0;
+    if (css) {
+        gchar const *property = css ? sp_repr_css_property(css, "opacity", "1.000") : 0;
            
-    if (desktop->current && property) { // if there is style and the property in it,
-        if ( !sp_svg_number_read_f(property, &value) ) {
-            value = 1.0; // things failed. set back to the default
+        if (desktop->current && property) { // if there is style and the property in it,
+            if ( !sp_svg_number_read_f(property, &value) ) {
+                value = 1.0; // things failed. set back to the default
+            }
         }
+
+        sp_repr_css_attr_unref(css);
     }
+
+    return value;
+}
+double
+sp_desktop_get_opacity_tool(SPDesktop *desktop, char const *tool, bool is_fill)
+{
+    SPCSSAttr *css = NULL;
+    gfloat value = 1.0; // default if nothing else found
+    if (prefs_get_double_attribute(tool, "usecurrent", 0) != 0) {
+        css = sp_desktop_get_style(desktop, true);
+    } else { 
+        Inkscape::XML::Node *tool_repr = inkscape_get_repr(INKSCAPE, tool);
+        if (tool_repr) {
+            css = sp_repr_css_attr_inherited(tool_repr, "style");
+        }
+    }
+   
+    if (css) {
+        gchar const *property = css ? sp_repr_css_property(css, is_fill ? "fill-opacity": "stroke-opacity", "1.000") : 0;
+           
+        if (desktop->current && property) { // if there is style and the property in it,
+            if ( !sp_svg_number_read_f(property, &value) ) {
+                value = 1.0; // things failed. set back to the default
+            }
+        }
+
+        sp_repr_css_attr_unref(css);
+    }
+
     return value;
 }
 guint32
@@ -247,24 +286,29 @@ sp_desktop_get_color_tool(SPDesktop *desktop, char const *tool, bool is_fill)
 {
     SPCSSAttr *css = NULL;
     guint32 r = 0; // if there's no color, return black
-    bool op = true;
-    double opacity = sp_desktop_get_opacity_tool(SP_ACTIVE_DESKTOP, "tools.calligraphic", op);
     if (prefs_get_int_attribute(tool, "usecurrent", 0) != 0) {
-        css = sp_desktop_get_style(desktop, is_fill);
+        css = sp_desktop_get_style(desktop, true);
     } else {
         Inkscape::XML::Node *tool_repr = inkscape_get_repr(INKSCAPE, tool);
-        css = sp_repr_css_attr_inherited(tool_repr, "style");
+        if (tool_repr) {
+            css = sp_repr_css_attr_inherited(tool_repr, "style");
+        }
     }
    
-    gchar const *property = sp_repr_css_property(css, is_fill ? "fill" : "stroke", "#000");
+    if (css) {
+        gchar const *property = sp_repr_css_property(css, is_fill ? "fill" : "stroke", "#000");
            
-    if (desktop->current && property) { // if there is style and the property in it,
-        if (strncmp(property, "url", 3)) { // and if it's not url,
-            // read it
-            r = sp_svg_read_color(property, r);
+        if (desktop->current && property) { // if there is style and the property in it,
+            if (strncmp(property, "url", 3)) { // and if it's not url,
+                // read it
+                r = sp_svg_read_color(property, r);
+            }
         }
+
+        sp_repr_css_attr_unref(css);
     }
-    return r | SP_COLOR_F_TO_U( opacity ); // return RGBA color
+
+    return r | 0xff;
 }
 /**
  * Apply the desktop's current style or the tool style to repr.
@@ -283,7 +327,8 @@ sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, char
             sp_repr_css_attr_unref(css);
         }
     }
-    if (css_current) {sp_repr_css_attr_unref(css_current);
+    if (css_current) {
+        sp_repr_css_attr_unref(css_current);
     }
 }
 
@@ -307,7 +352,7 @@ sp_desktop_get_font_size_tool(SPDesktop *desktop)
 
     double ret = 12;
     if (style_str) {
-        SPStyle *style = sp_style_new();
+        SPStyle *style = sp_style_new(SP_ACTIVE_DOCUMENT);
         sp_style_merge_from_style_string(style, style_str);
         ret = style->font_size.computed;
         sp_style_unref(style);
@@ -370,8 +415,8 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill
     c[0] = c[1] = c[2] = c[3] = 0.0;
     gint num = 0;
 
-    gfloat prev[4];
-    prev[0] = prev[1] = prev[2] = prev[3] = 0.0;
+    gfloat prev[3];
+    prev[0] = prev[1] = prev[2] = 0.0;
     bool same_color = true;
 
     for (GSList const *i = objects; i != NULL; i = i->next) {
@@ -383,7 +428,10 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill
 
         // We consider paint "effectively set" for anything within text hierarchy
         SPObject *parent = SP_OBJECT_PARENT (obj);
-        bool paint_effectively_set = paint->set || (SP_IS_TEXT(parent) || SP_IS_TEXTPATH(parent) || SP_IS_TSPAN(parent) || SP_IS_FLOWTEXT(parent) || SP_IS_FLOWDIV(parent) || SP_IS_FLOWPARA(parent) || SP_IS_FLOWTSPAN(parent) || SP_IS_FLOWLINE(parent));
+        bool paint_effectively_set = 
+            paint->set || (SP_IS_TEXT(parent) || SP_IS_TEXTPATH(parent) || SP_IS_TSPAN(parent)
+            || SP_IS_FLOWTEXT(parent) || SP_IS_FLOWDIV(parent) || SP_IS_FLOWPARA(parent) 
+            || SP_IS_FLOWTSPAN(parent) || SP_IS_FLOWLINE(parent));
 
         // 1. Bail out with QUERY_STYLE_MULTIPLE_DIFFERENT if necessary
 
@@ -441,9 +489,8 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill
                 prev[0] = d[0];
                 prev[1] = d[1];
                 prev[2] = d[2];
-                prev[3] = d[3];
             } else {
-                if (same_color && (prev[0] != d[0] || prev[1] != d[1] || prev[2] != d[2] || prev[3] != d[3]))
+                if (same_color && (prev[0] != d[0] || prev[1] != d[1] || prev[2] != d[2]))
                     same_color = false;
             }
 
@@ -455,14 +502,14 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill
             num ++;
         }
 
+       paint_res->type = paint->type;
        if (paint_res->set && paint_effectively_set && paint->type == SP_PAINT_TYPE_PAINTSERVER) { // copy the server
            if (isfill) {
-               SP_STYLE_FILL_SERVER (style_res) = SP_STYLE_FILL_SERVER (style);
+               sp_style_set_to_uri_string (style_res, true, style->getFillURI());
            } else {
-               SP_STYLE_STROKE_SERVER (style_res) = SP_STYLE_STROKE_SERVER (style);
+               sp_style_set_to_uri_string (style_res, false, style->getStrokeURI());
            }
        }
-       paint_res->type = paint->type;
        paint_res->set = paint_effectively_set;
        style_res->fill_rule.computed = style->fill_rule.computed; // no averaging on this, just use the last one
     }
@@ -783,7 +830,7 @@ objects_query_fontnumbers (GSList *objects, SPStyle *style_res)
         SPObject *obj = SP_OBJECT (i->data);
 
         if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj)
-            && !SP_IS_TSPAN(obj) && !SP_IS_TEXTPATH(obj)
+            && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj)
             && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj))
             continue;
 
@@ -876,7 +923,7 @@ objects_query_fontstyle (GSList *objects, SPStyle *style_res)
         SPObject *obj = SP_OBJECT (i->data);
 
         if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj)
-            && !SP_IS_TSPAN(obj) && !SP_IS_TEXTPATH(obj)
+            && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj)
             && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj))
             continue;
 
@@ -895,6 +942,7 @@ objects_query_fontstyle (GSList *objects, SPStyle *style_res)
         style_res->font_style.value = style_res->font_style.computed = style->font_style.computed;
         style_res->font_stretch.value = style_res->font_stretch.computed = style->font_stretch.computed;
         style_res->font_variant.value = style_res->font_variant.computed = style->font_variant.computed;
+        style_res->text_align.value = style_res->text_align.computed = style->text_align.computed;
     }
 
     if (texts == 0 || !set)
@@ -930,7 +978,7 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res)
         SPObject *obj = SP_OBJECT (i->data);
 
         if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj)
-            && !SP_IS_TSPAN(obj) && !SP_IS_TEXTPATH(obj)
+            && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj)
             && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj))
             continue;
 
@@ -967,6 +1015,154 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res)
     }
 }
 
+int
+objects_query_blend (GSList *objects, SPStyle *style_res)
+{
+    const int empty_prev = -2;
+    const int complex_filter = 5;
+    int blend = 0;
+    float blend_prev = empty_prev;
+    bool same_blend = true;
+    guint items = 0;
+    
+    for (GSList const *i = objects; i != NULL; i = i->next) {
+        SPObject *obj = SP_OBJECT (i->data);
+        SPStyle *style = SP_OBJECT_STYLE (obj);
+        if(!style || !SP_IS_ITEM(obj)) continue;
+
+        items++;
+
+        //if object has a filter
+        if (style->filter.set && style->getFilter()) {
+            int blurcount = 0;
+            int blendcount = 0;
+
+            // determine whether filter is simple (blend and/or blur) or complex
+            for(SPObject *primitive_obj = style->getFilter()->children;
+                primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj);
+                primitive_obj = primitive_obj->next) {
+                SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj);
+                if(SP_IS_FEBLEND(primitive))
+                    ++blendcount;
+                else if(SP_IS_GAUSSIANBLUR(primitive))
+                    ++blurcount;
+                else {
+                    blurcount = complex_filter;
+                    break;
+                }
+            }
+
+            // simple filter
+            if(blurcount == 1 || blendcount == 1) {
+                for(SPObject *primitive_obj = style->getFilter()->children;
+                    primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj);
+                    primitive_obj = primitive_obj->next) {
+                    if(SP_IS_FEBLEND(primitive_obj)) {
+                        SPFeBlend *spblend = SP_FEBLEND(primitive_obj);
+                        blend = spblend->blend_mode;
+                    }
+                }
+            }
+            else {
+                blend = complex_filter;
+            }
+        }
+        // defaults to blend mode = "normal"
+        else {
+            blend = 0;
+        }
+
+        if(blend_prev != empty_prev && blend_prev != blend)
+            same_blend = false;
+        blend_prev = blend;
+    }
+
+    if (items > 0) {
+        style_res->filter_blend_mode.value = blend;
+    }
+
+    if (items == 0) {
+        return QUERY_STYLE_NOTHING;
+    } else if (items == 1) {
+        return QUERY_STYLE_SINGLE;
+    } else {
+        if(same_blend)
+            return QUERY_STYLE_MULTIPLE_SAME;
+        else
+            return QUERY_STYLE_MULTIPLE_DIFFERENT;
+    }
+}
+
+/**
+ * Write to style_res the average blurring of a list of objects.
+ */
+int
+objects_query_blur (GSList *objects, SPStyle *style_res)
+{
+   if (g_slist_length(objects) == 0) {
+        /* No objects, set empty */
+        return QUERY_STYLE_NOTHING;
+    }
+
+    float blur_sum = 0;
+    float blur_prev = -1;
+    bool same_blur = true;
+    guint blur_items = 0;
+    guint items = 0;
+    
+    for (GSList const *i = objects; i != NULL; i = i->next) {
+        SPObject *obj = SP_OBJECT (i->data);
+        SPStyle *style = SP_OBJECT_STYLE (obj);
+        if (!style) continue;
+        if (!SP_IS_ITEM(obj)) continue;
+
+        NR::Matrix i2d = sp_item_i2d_affine (SP_ITEM(obj));
+
+        items ++;
+
+        //if object has a filter
+        if (style->filter.set && style->getFilter()) {
+            //cycle through filter primitives
+            SPObject *primitive_obj = style->getFilter()->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) {
+        if (blur_items > 0)
+            blur_sum /= blur_items;
+        style_res->filter_gaussianBlur_deviation.value = blur_sum;
+    }
+
+    if (items == 0) {
+        return QUERY_STYLE_NOTHING;
+    } else if (items == 1) {
+        return QUERY_STYLE_SINGLE;
+    } else {
+        if (same_blur)
+            return QUERY_STYLE_MULTIPLE_SAME;
+        else
+            return QUERY_STYLE_MULTIPLE_AVERAGED;
+    }
+}
+
 /**
  * Query the given list of objects for the given property, write
  * the result to style, return appropriate flag.
@@ -997,8 +1193,12 @@ sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property)
         return objects_query_fontstyle (list, style);
     } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) {
         return objects_query_fontnumbers (list, style);
-    }
 
+    } else if (property == QUERY_STYLE_PROPERTY_BLEND) {
+        return objects_query_blend (list, style);
+    } else if (property == QUERY_STYLE_PROPERTY_BLUR) {
+        return objects_query_blur (list, style);
+    }
     return QUERY_STYLE_NOTHING;
 }
 
@@ -1036,8 +1236,9 @@ sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query)
         int result_strokecap = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_STROKECAP);
         int result_strokejoin = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_STROKEJOIN);
         int result_opacity = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
-
-        return (result_family != QUERY_STYLE_NOTHING && result_fstyle != QUERY_STYLE_NOTHING && result_fnumbers != QUERY_STYLE_NOTHING && result_fill != QUERY_STYLE_NOTHING && result_stroke != QUERY_STYLE_NOTHING && result_opacity != QUERY_STYLE_NOTHING && result_strokewidth != QUERY_STYLE_NOTHING && result_strokemiterlimit != QUERY_STYLE_NOTHING && result_strokecap != QUERY_STYLE_NOTHING && result_strokejoin != QUERY_STYLE_NOTHING);
+        int result_blur = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLUR);
+        
+        return (result_family != QUERY_STYLE_NOTHING && result_fstyle != QUERY_STYLE_NOTHING && result_fnumbers != QUERY_STYLE_NOTHING && result_fill != QUERY_STYLE_NOTHING && result_stroke != QUERY_STYLE_NOTHING && result_opacity != QUERY_STYLE_NOTHING && result_strokewidth != QUERY_STYLE_NOTHING && result_strokemiterlimit != QUERY_STYLE_NOTHING && result_strokecap != QUERY_STYLE_NOTHING && result_strokejoin != QUERY_STYLE_NOTHING && result_blur != QUERY_STYLE_NOTHING);
 }