Code

Fixed rendering glitch in bicubic scaler
[inkscape.git] / src / filter-chemistry.cpp
index 90a6e32f2ca4aede9b6bb2d7aa716ed8489f7f02..e0dbee9ea8b8b2ef41d92ba78038c0c4e0faa2b1 100644 (file)
 #include "document-private.h"
 #include "desktop-style.h"
 
+#include "filter-chemistry.h"
+#include "filter-enums.h"
+
+#include "sp-feblend.h"
 #include "sp-filter.h"
+#include "sp-filter-reference.h"
 #include "sp-gaussian-blur.h"
 #include "svg/css-ostringstream.h"
 
@@ -39,7 +44,7 @@ count_filter_hrefs(SPObject *o, SPFilter *filter)
     SPStyle *style = SP_OBJECT_STYLE(o);
     if (style
         && style->filter.set
-        && style->filter.filter == filter)
+        && style->getFilter() == filter)
     {
         i ++;
     }
@@ -82,6 +87,99 @@ static void set_filter_area(Inkscape::XML::Node *repr, gdouble radius,
     }
 }
 
+SPFilter *new_filter(SPDocument *document)
+{
+    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");
+
+    // Append the new filter node to defs
+    SP_OBJECT_REPR(defs)->appendChild(repr);
+    Inkscape::GC::release(repr);
+
+    // get corresponding object
+    SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
+    
+    
+    g_assert(f != NULL);
+    g_assert(SP_IS_FILTER(f));
+
+    return f;
+}
+
+SPFilterPrimitive *
+filter_add_primitive(SPFilter *filter, const NR::FilterPrimitiveType type)
+{
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(filter->document);
+
+    //create filter primitive node
+    Inkscape::XML::Node *repr;
+    repr = xml_doc->createElement(FPConverter.get_key(type).c_str());
+    repr->setAttribute("inkscape:collect", "always");
+
+    // set default values
+    switch(type) {
+        case NR::NR_FILTER_BLEND:
+            repr->setAttribute("blend", "normal");
+            break;
+        case NR::NR_FILTER_COLORMATRIX:
+            break;
+        case NR::NR_FILTER_COMPONENTTRANSFER:
+            break;
+        case NR::NR_FILTER_COMPOSITE:
+            break;
+        case NR::NR_FILTER_CONVOLVEMATRIX:
+            repr->setAttribute("order", "3 3");
+            repr->setAttribute("kernelMatrix", "0 0 0 0 0 0 0 0 0");
+            break;
+        case NR::NR_FILTER_DIFFUSELIGHTING:
+            break;
+        case NR::NR_FILTER_DISPLACEMENTMAP:
+            break;
+        case NR::NR_FILTER_FLOOD:
+            break;
+        case NR::NR_FILTER_GAUSSIANBLUR:
+            repr->setAttribute("stdDeviation", "1");
+            break;
+        case NR::NR_FILTER_IMAGE:
+            break;
+        case NR::NR_FILTER_MERGE:
+            break;
+        case NR::NR_FILTER_MORPHOLOGY:
+            break;
+        case NR::NR_FILTER_OFFSET:
+            repr->setAttribute("dx", "0");
+            repr->setAttribute("dy", "0");
+            break;
+        case NR::NR_FILTER_SPECULARLIGHTING:
+            break;
+        case NR::NR_FILTER_TILE:
+            break;
+        case NR::NR_FILTER_TURBULENCE:
+            break;
+        default:
+            break;
+    }
+
+    //set primitive as child of filter node
+    filter->repr->appendChild(repr);
+    Inkscape::GC::release(repr);
+    
+    // get corresponding object
+    SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE( filter->document->getObjectByRepr(repr) );
+    g_assert(prim != NULL);
+    g_assert(SP_IS_FILTER_PRIMITIVE(prim));
+
+    return prim;
+}
+
 /**
  * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height
  */
@@ -134,11 +232,92 @@ new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion
     return f;
 }
 
+
+/**
+ * Creates a simple filter with a blend primitive and a blur primitive of specified radius for
+ * an item with the given matrix expansion, width and height
+ */
+SPFilter *
+new_filter_blend_gaussian_blur (SPDocument *document, const char *blendmode, 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");
+
+    // Append the new filter node to defs
+    SP_OBJECT_REPR(defs)->appendChild(repr);
+    Inkscape::GC::release(repr);
+    // get corresponding object
+    SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
+
+    // Gaussian blur primitive
+    if(radius != 0) {
+        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");
+        
+        double stdDeviation = radius;
+        if (expansion != 0)
+            stdDeviation /= expansion;
+        
+        //set stdDeviation attribute
+        sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation);
+     
+        //set feGaussianBlur as child of filter node
+        repr->appendChild(b_repr);
+        Inkscape::GC::release(b_repr);
+
+        SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) );
+        g_assert(b != NULL);
+        g_assert(SP_IS_GAUSSIANBLUR(b));
+    }
+    // Blend primitive
+    if(strcmp(blendmode, "normal")) {
+        Inkscape::XML::Node *b_repr;
+        b_repr = xml_doc->createElement("svg:feBlend");
+        b_repr->setAttribute("inkscape:collect", "always");
+        b_repr->setAttribute("mode", blendmode);
+        b_repr->setAttribute("in2", "BackgroundImage");
+
+        // set feBlend as child of filter node
+        repr->appendChild(b_repr);
+        Inkscape::GC::release(b_repr);
+
+        // Enable background image buffer for document
+        Inkscape::XML::Node *root = b_repr->root();
+        if (!root->attribute("enable-background")) {
+            root->setAttribute("enable-background", "new");
+        }
+
+        SPFeBlend *b = SP_FEBLEND(document->getObjectByRepr(b_repr));
+        g_assert(b != NULL);
+        g_assert(SP_IS_FEBLEND(b));
+    }
+    
+    g_assert(f != NULL);
+    g_assert(SP_IS_FILTER(f));
+    return f;
+}
+
 /**
- * Creates a filter with blur primitive of specified radius for the given item
+ * Creates a simple filter for the given item with blend and blur primitives, using the
+ * specified mode and radius, respectively
  */
 SPFilter *
-new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble radius)
+new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble radius)
 {
     NR::Maybe<NR::Rect> const r = sp_item_bbox_desktop(item);
 
@@ -153,7 +332,7 @@ new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble
 
     NR::Matrix i2d = sp_item_i2d_affine (item);
 
-    return (new_filter_gaussian_blur (document, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height));
+    return (new_filter_blend_gaussian_blur (document, mode, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height));
 }
 
 /**
@@ -170,16 +349,16 @@ 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);
+        //return new_filter_gaussian_blur_from_item(document, item, radius);
     }
 
-    SPFilter *filter = SP_FILTER(item->style->filter.filter);
+    SPFilter *filter = SP_FILTER(item->style->getFilter());
     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);
+        repr = SP_OBJECT_REPR(item->style->getFilter())->duplicate(xml_doc);
         SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
         SP_OBJECT_REPR(defs)->appendChild(repr);
 
@@ -206,7 +385,7 @@ modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *item,
     }
 
     // Set the filter effects area
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->filter.filter);
+    Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->getFilter());
     set_filter_area(repr, radius, expansion, i2d.expansionX(),
                     i2d.expansionY(), width, height);
 
@@ -259,9 +438,9 @@ void remove_filter (SPObject *item, bool recursive)
  * be handled gracefully */
 void remove_filter_gaussian_blur (SPObject *item)
 {
-    if (item->style && item->style->filter.set && item->style->filter.filter) {
+    if (item->style && item->style->filter.set && item->style->getFilter()) {
         // 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 *repr = SP_OBJECT_REPR(item->style->getFilter());
         Inkscape::XML::Node *primitive = repr->firstChild();
         while (primitive) {
             if (strcmp("svg:feGaussianBlur", primitive->name()) == 0) {