summaryrefslogtreecommitdiffstats
path: root/src/filter-chemistry.cpp
blob: 164a6594a71fe16c483f979921c2cd6be995603a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#define __SP_FILTER_CHEMISTRY_C__

/*
 * Various utility methods for filters
 *
 * Authors:
 *   Hugo Rodrigues
 *   bulia byak
 *
 * Copyright (C) 2006 authors
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */


#include "style.h"
#include "document-private.h"
#include "desktop-style.h"

#include "sp-filter.h"
#include "sp-gaussian-blur.h"
#include "svg/css-ostringstream.h"

#include "xml/repr.h"

/**
 * 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");

    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
        // http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion), specify margins
        // The 2.4 is an empirical coefficient: at that distance the cutoff is practically invisible 
        // (the opacity at 2.4*radius is about 3e-3)
        double xmargin = 2.4 * (rx) / width;
        double ymargin = 2.4 * (ry) / height;

        // TODO: set it in UserSpaceOnUse instead?
        sp_repr_set_svg_double(repr, "x", -xmargin);
        sp_repr_set_svg_double(repr, "width", 1 + 2 * xmargin);
        sp_repr_set_svg_double(repr, "y", -ymargin);
        sp_repr_set_svg_double(repr, "height", 1 + 2 * ymargin);
    }

    //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);
    
    // 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) );
    SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) );
    
    g_assert(f != NULL);
    g_assert(SP_IS_FILTER(f));
    g_assert(b != NULL);
    g_assert(SP_IS_GAUSSIANBLUR(b));

    return f;
}

/**
 * Creates a filter with blur primitive of specified radius for the given item
 */
SPFilter *
new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble radius)
{
    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;
    }

    NR::Matrix i2d = sp_item_i2d_affine (item);

    return (new_filter_gaussian_blur (document, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height));
}

void remove_filter (SPObject *item, bool recursive)
{
	SPCSSAttr *css = sp_repr_css_attr_new ();
	sp_repr_css_unset_property (css, "filter");
	if (recursive)
		sp_repr_css_change_recursive(SP_OBJECT_REPR(item), css, "style");
	else
		sp_repr_css_change (SP_OBJECT_REPR(item), css, "style");
      sp_repr_css_attr_unref (css);
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :