Code

7e558dd6ce306d021d95dbd267e95eab5cc85a7d
[inkscape.git] / src / display / nr-filter.cpp
1 #define __NR_FILTER_CPP__
3 /*
4  * SVG filters rendering
5  *
6  * Author:
7  *   Niko Kiirala <niko@kiirala.com>
8  *
9  * Copyright (C) 2006 Niko Kiirala
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #include "display/nr-filter.h"
15 #include "display/nr-filter-primitive.h"
16 #include "display/nr-filter-gaussian.h"
17 #include "display/nr-filter-slot.h"
18 #include "display/nr-filter-types.h"
20 #include "display/nr-arena-item.h"
21 #include "libnr/nr-pixblock.h"
22 #include "libnr/nr-blit.h"
23 #include "svg/svg-length.h"
24 #include "sp-filter-units.h"
26 //#include "display/nr-arena-shape.h"
28 namespace NR {
30 Filter::Filter()
31 {
32     _primitive_count = 1;
33     _primitive_table_size = 1;
34     _primitive = new FilterPrimitive*[1];
35     _primitive[0] = new FilterGaussian;
36     _common_init();
37 }
39 Filter::Filter(int n)
40 {
41     _primitive_count = 0;
42     _primitive_table_size = n;
43     _primitive = new FilterPrimitive*[n];
44     for ( int i = 0 ; i < n ; i++ ) {
45         _primitive[i] = NULL;
46     }
47     _common_init();
48 }
50 void Filter::_common_init() {
51     _slot_count = 1;
52     _output_slot = NR_FILTER_SLOT_NOT_SET;
54     _region_x.set(SVGLength::PERCENT, -10, 0);
55     _region_y.set(SVGLength::PERCENT, -10, 0);
56     _region_width.set(SVGLength::PERCENT, 120, 0);
57     _region_height.set(SVGLength::PERCENT, 120, 0);
59     _x_pixels = -1.0;
60     _y_pixels = -1.0;
62     _filter_units = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
63     _primitive_units = SP_FILTER_UNITS_USERSPACEONUSE;
64 }
66 Filter::~Filter()
67 {
68     clear_primitives();
69     delete[] _primitive;
70 }
73 int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
74 {
75     FilterSlot slot(_slot_count);
76     NRPixBlock *in = new NRPixBlock;
77     nr_pixblock_setup_fast(in, pb->mode,
78                            pb->area.x0, pb->area.y0,
79                            pb->area.x1, pb->area.y1, true);
80     nr_blit_pixblock_pixblock(in, pb);
81     slot.set(NR_FILTER_SOURCEGRAPHIC, in);
82     in = NULL; // in is now handled by FilterSlot, we should not touch it
84     _primitive[0]->render(slot, *item->ctm);
86     NRPixBlock *out = slot.get(_output_slot);
88     int size = (pb->area.x1 - pb->area.x0)
89         * (pb->area.y1 - pb->area.y0)
90         * NR_PIXBLOCK_BPP(pb);
91     memset(NR_PIXBLOCK_PX(pb), 0, size);
93     nr_blit_pixblock_pixblock(pb, out);
95     _slot_count = slot.get_slot_count();
96     return 0;
97 }
99 int Filter::get_enlarge(Matrix const &m)
101     int enlarge = 0;
102     for ( int i = 0 ; i < _primitive_count ; i++ ) {
103         if(_primitive[i]) enlarge += _primitive[i]->get_enlarge(m);
104     }
105     return enlarge;
108 void Filter::bbox_enlarge(NRRectL &bbox)
110     int len_x = bbox.x1 - bbox.x0;
111     int len_y = bbox.y1 - bbox.y0;
112     int enlarge_x = (int)std::ceil(len_x / 10.0);
113     int enlarge_y = (int)std::ceil(len_y / 10.0);
114     bbox.x0 -= enlarge_x;
115     bbox.x1 += enlarge_x;
116     bbox.y0 -= enlarge_y;
117     bbox.y1 += enlarge_y;
120 typedef FilterPrimitive*(*FilterConstructor)();
121 static FilterConstructor _constructor[NR_FILTER_ENDPRIMITIVETYPE];
123 void Filter::_create_constructor_table()
125     static bool created = false;
126     if(created) return;
128     /* Filter effects not yet implemented are set to NULL */
129     _constructor[NR_FILTER_BLEND] = NULL;
130     _constructor[NR_FILTER_COLORMATRIX] = NULL;
131     _constructor[NR_FILTER_COMPONENTTRANSFER] = NULL;
132     _constructor[NR_FILTER_COMPOSITE] = NULL;
133     _constructor[NR_FILTER_CONVOLVEMATRIX] = NULL;
134     _constructor[NR_FILTER_DIFFUSELIGHTING] = NULL;
135     _constructor[NR_FILTER_DISPLACEMENTMAP] = NULL;
136     _constructor[NR_FILTER_FLOOD] = NULL;
137     _constructor[NR_FILTER_GAUSSIANBLUR] = &FilterGaussian::create;
138     _constructor[NR_FILTER_IMAGE] = NULL;
139     _constructor[NR_FILTER_MERGE] = NULL;
140     _constructor[NR_FILTER_MORPHOLOGY] = NULL;
141     _constructor[NR_FILTER_OFFSET] = NULL;
142     _constructor[NR_FILTER_SPECULARLIGHTING] = NULL;
143     _constructor[NR_FILTER_TILE] = NULL;
144     _constructor[NR_FILTER_TURBULENCE] = NULL;
147 void Filter::_enlarge_primitive_table() {
148     FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2];
149     for (int i = 0 ; i < _primitive_count ; i++) {
150         new_tbl[i] = _primitive[i];
151     }
152     _primitive_table_size *= 2;
153     for (int i = _primitive_count ; i < _primitive_table_size ; i++) {
154         new_tbl[i] = NULL;
155     }
156     delete[] _primitive;
157     _primitive = new_tbl;
160 FilterPrimitive *Filter::add_primitive(FilterPrimitiveType type)
162     _create_constructor_table();
164     // Check that we can create a new filter of specified type
165     if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE)
166         return NULL;
167     if (!_constructor[type]) return NULL;
168     FilterPrimitive *created = _constructor[type]();
170     // If there is no space for new filter primitive, enlarge the table
171     if (_primitive_count >= _primitive_table_size) {
172         _enlarge_primitive_table();
173     }
175     _primitive[_primitive_count] = created;
176     return created;
179 FilterPrimitive *Filter::replace_primitive(FilterPrimitive *target, FilterPrimitiveType type)
181     _create_constructor_table();
183     // Check that target is valid primitive inside this filter
184     int place = -1;
185     for (int i = 0 ; i < _primitive_count ; i++) {
186         if (target == _primitive[i]) {
187             place = i;
188             break;
189         }
190     }
191     if (place < 0) return NULL;
193     // Check that we can create a new filter of specified type
194     if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE)
195         return NULL;
196     if (!_constructor[type]) return NULL;
197     FilterPrimitive *created = _constructor[type]();
199     // If there is no space for new filter primitive, enlarge the table
200     if (_primitive_count >= _primitive_table_size) {
201         _enlarge_primitive_table();
202     }
204     delete target;
205     _primitive[place] = created;
206     return created;
209 void Filter::clear_primitives()
211     for (int i = 0 ; i < _primitive_count ; i++) {
212         if (_primitive[i]) delete _primitive[i];
213     }
214     _primitive_count = 0;
217 } /* namespace NR */
219 /*
220   Local Variables:
221   mode:c++
222   c-file-style:"stroustrup"
223   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
224   indent-tabs-mode:nil
225   fill-column:99
226   End:
227 */
228 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :