39
38
#include "display/nr-filter-tile.h"
40
39
#include "display/nr-filter-turbulence.h"
42
#include "display/nr-arena.h"
43
#include "display/nr-arena-item.h"
44
#include "libnr/nr-pixblock.h"
45
#include "libnr/nr-blit.h"
46
#include <2geom/matrix.h>
41
#include "display/drawing.h"
42
#include "display/drawing-item.h"
43
#include "display/drawing-context.h"
44
#include <2geom/affine.h>
47
45
#include <2geom/rect.h>
48
46
#include "svg/svg-length.h"
49
47
#include "sp-filter-units.h"
63
static Geom::OptRect get_item_bbox(NRArenaItem const *item) {
65
if (item->item_bbox) {
66
item_bbox = *(item->item_bbox);
68
// Bounding box might not exist, so create a dummy one.
69
Geom::Point zero(0, 0);
70
item_bbox = Geom::Rect(zero, zero);
72
if (item_bbox.min()[X] > item_bbox.max()[X]
73
|| item_bbox.min()[Y] > item_bbox.max()[Y])
75
// In case of negative-size bbox, return an empty OptRect
76
return Geom::OptRect();
78
return Geom::OptRect(item_bbox);
84
_primitive_table_size = 1;
85
_primitive = new FilterPrimitive*[1];
87
//_primitive_count = 1;
88
//_primitive[0] = new FilterGaussian;
92
66
Filter::Filter(int n)
95
_primitive_table_size = (n > 0) ? n : 1; // we guarantee there is at least 1(one) filter slot
96
_primitive = new FilterPrimitive*[_primitive_table_size];
97
for ( int i = 0 ; i < _primitive_table_size ; i++ ) {
68
if (n > 0) _primitive.reserve(n);
127
96
clear_primitives();
132
int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
100
int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct)
134
if (!_primitive[0]) {
135
// TODO: Should clear the input buffer instead of just returning
139
FilterQuality const filterquality = (FilterQuality)item->arena->filterquality;
140
int const blurquality = item->arena->blurquality;
142
Geom::Matrix trans = item->ctm;
143
FilterSlot slot(_slot_count, item);
144
slot.set_quality(filterquality);
145
slot.set_blurquality(blurquality);
147
Geom::Rect item_bbox;
149
Geom::OptRect maybe_bbox = get_item_bbox(item);
150
if (maybe_bbox.isEmpty()) {
151
// Code below needs a bounding box
154
item_bbox = *maybe_bbox;
157
Geom::Rect filter_area = filter_effect_area(item_bbox);
158
if (item_bbox.hasZeroArea()) {
159
// It's no use to try and filter an empty object.
102
if (_primitive.empty()) {
103
// when no primitives are defined, clear source graphic
104
graphic.setSource(0,0,0,0);
105
graphic.setOperator(CAIRO_OPERATOR_SOURCE);
107
graphic.setOperator(CAIRO_OPERATOR_OVER);
111
FilterQuality const filterquality = (FilterQuality)item->drawing().filterQuality();
112
int const blurquality = item->drawing().blurQuality();
114
Geom::Affine trans = item->ctm();
116
Geom::OptRect filter_area = filter_effect_area(item->itemBounds());
117
if (!filter_area) return 1;
163
119
FilterUnits units(_filter_units, _primitive_units);
164
120
units.set_ctm(trans);
165
units.set_item_bbox(item_bbox);
166
units.set_filter_area(filter_area);
121
units.set_item_bbox(item->itemBounds());
122
units.set_filter_area(*filter_area);
168
// TODO: with filterRes of 0x0 should return an empty image
169
124
std::pair<double,double> resolution
170
= _filter_resolution(filter_area, trans, filterquality);
171
if(!(resolution.first > 0 && resolution.second > 0))
125
= _filter_resolution(*filter_area, trans, filterquality);
126
if (!(resolution.first > 0 && resolution.second > 0)) {
127
// zero resolution - clear source graphic and return
128
graphic.setSource(0,0,0,0);
129
graphic.setOperator(CAIRO_OPERATOR_SOURCE);
131
graphic.setOperator(CAIRO_OPERATOR_OVER);
173
135
units.set_resolution(resolution.first, resolution.second);
174
136
if (_x_pixels > 0) {
175
137
units.set_automatic_resolution(false);
181
143
units.set_paraller(false);
182
for (int i = 0 ; i < _primitive_count ; i++) {
183
if (_primitive[i]->get_input_traits() & TRAIT_PARALLER) {
144
Geom::Affine pbtrans = units.get_matrix_display2pb();
145
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
146
if (!_primitive[i]->can_handle_affine(pbtrans)) {
184
147
units.set_paraller(true);
189
slot.set_units(units);
191
NRPixBlock *in = new NRPixBlock;
192
nr_pixblock_setup_fast(in, pb->mode, pb->area.x0, pb->area.y0,
193
pb->area.x1, pb->area.y1, true);
194
if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) {
195
g_warning("Inkscape::Filters::Filter::render: failed to reserve temporary buffer");
198
nr_blit_pixblock_pixblock(in, pb);
200
slot.set(NR_FILTER_SOURCEGRAPHIC, in);
202
// Check that we are rendering a non-empty area
203
in = slot.get(NR_FILTER_SOURCEGRAPHIC);
204
if (in->area.x1 - in->area.x0 <= 0 || in->area.y1 - in->area.y0 <= 0) {
205
if (in->area.x1 - in->area.x0 < 0 || in->area.y1 - in->area.y0 < 0) {
206
g_warning("Inkscape::Filters::Filter::render: negative area! (%d, %d) (%d, %d)",
207
in->area.x0, in->area.y0, in->area.x1, in->area.y1);
211
in = NULL; // in is now handled by FilterSlot, we should not touch it
213
for (int i = 0 ; i < _primitive_count ; i++) {
214
_primitive[i]->render(slot, units);
217
slot.get_final(_output_slot, pb);
219
// Take note of the amount of used image slots
220
// -> next time this filter is rendered, we can reserve enough slots
222
_slot_count = slot.get_slot_count();
152
FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgct, graphic, units);
153
slot.set_quality(filterquality);
154
slot.set_blurquality(blurquality);
156
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
157
_primitive[i]->render_cairo(slot);
160
Geom::Point origin = graphic.targetLogicalBounds().min();
161
cairo_surface_t *result = slot.get_result(_output_slot);
162
graphic.setSource(result, origin[Geom::X], origin[Geom::Y]);
163
graphic.setOperator(CAIRO_OPERATOR_SOURCE);
165
graphic.setOperator(CAIRO_OPERATOR_OVER);
166
cairo_surface_destroy(result);
231
176
_primitive_units = unit;
234
void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
235
for (int i = 0 ; i < _primitive_count ; i++) {
236
if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm);
179
void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item) const {
180
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
181
if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm());
239
185
TODO: something. See images at the bottom of filters.svg with medium-low
240
186
filtering quality.
256
202
item_bbox = *maybe_bbox;
258
204
std::pair<double,double> res_low
259
= _filter_resolution(item_bbox, item->ctm, filterquality);
205
= _filter_resolution(item_bbox, item->ctm(), filterquality);
260
206
//std::pair<double,double> res_full
261
// = _filter_resolution(item_bbox, item->ctm, FILTER_QUALITY_BEST);
207
// = _filter_resolution(item_bbox, item->ctm(), FILTER_QUALITY_BEST);
262
208
double pixels_per_block = fmax(item_bbox.width() / res_low.first,
263
209
item_bbox.height() / res_low.second);
264
210
bbox.x0 -= (int)pixels_per_block;
271
void Filter::bbox_enlarge(NRRectL &bbox) {
272
// Modifying empty bounding boxes confuses rest of the renderer, so
273
// let's not do that.
274
if (bbox.x0 > bbox.x1 || bbox.y0 > bbox.y1) return;
276
/* TODO: this is wrong. Should use bounding box in user coordinates
277
* and find its extents in display coordinates. */
278
Geom::Point min(bbox.x0, bbox.y0);
279
Geom::Point max(bbox.x1, bbox.y1);
280
Geom::Rect tmp_bbox(min, max);
282
Geom::Rect enlarged = filter_effect_area(tmp_bbox);
284
bbox.x0 = (NR::ICoord)enlarged.min()[X];
285
bbox.y0 = (NR::ICoord)enlarged.min()[Y];
286
bbox.x1 = (NR::ICoord)enlarged.max()[X];
287
bbox.y1 = (NR::ICoord)enlarged.max()[Y];
217
Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) {
219
Geom::OptRect enlarged = filter_effect_area(item_bbox);
221
*enlarged *= item->ctm();
223
Geom::OptIntRect ret(enlarged->roundOutwards());
226
return Geom::OptIntRect();
290
Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
230
Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox)
292
232
Geom::Point minp, maxp;
293
double len_x = bbox.max()[X] - bbox.min()[X];
294
double len_y = bbox.max()[Y] - bbox.min()[Y];
233
double len_x = bbox ? bbox->width() : 0;
234
double len_y = bbox ? bbox->height() : 0;
295
235
/* TODO: fetch somehow the object ex and em lengths */
296
236
_region_x.update(12, 6, len_x);
297
237
_region_y.update(12, 6, len_y);
298
238
_region_width.update(12, 6, len_x);
299
239
_region_height.update(12, 6, len_y);
300
240
if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
241
if (!bbox) return Geom::OptRect();
301
243
if (_region_x.unit == SVGLength::PERCENT) {
302
minp[X] = bbox.min()[X] + _region_x.computed;
244
minp[X] = bbox->left() + _region_x.computed;
304
minp[X] = bbox.min()[X] + _region_x.computed * len_x;
246
minp[X] = bbox->left() + _region_x.computed * len_x;
306
248
if (_region_width.unit == SVGLength::PERCENT) {
307
249
maxp[X] = minp[X] + _region_width.computed;
312
254
if (_region_y.unit == SVGLength::PERCENT) {
313
minp[Y] = bbox.min()[Y] + _region_y.computed;
255
minp[Y] = bbox->top() + _region_y.computed;
315
minp[Y] = bbox.min()[Y] + _region_y.computed * len_y;
257
minp[Y] = bbox->top() + _region_y.computed * len_y;
317
259
if (_region_height.unit == SVGLength::PERCENT) {
318
260
maxp[Y] = minp[Y] + _region_height.computed;
326
268
minp[Y] = _region_y.computed;
327
269
maxp[Y] = minp[Y] + _region_height.computed;
329
g_warning("Error in Inkscape::Filters::Filter::bbox_enlarge: unrecognized value of _filter_units");
271
g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units");
331
Geom::Rect area(minp, maxp);
273
Geom::OptRect area(minp, maxp);
277
double Filter::complexity(Geom::Affine const &ctm)
280
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
282
double f = _primitive[i]->complexity(ctm);
289
bool Filter::uses_background()
291
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
292
if (_primitive[i] && _primitive[i]->uses_background()) {
335
299
/* Constructor table holds pointers to static methods returning filter
336
300
* primitives. This table is indexed with FilterPrimitiveType, so that
337
301
* for example method in _constructor[NR_FILTER_GAUSSIANBLUR]
370
/** Helper method for enlarging table of filter primitives. When new
371
* primitives are added, but we have no space for them, this function
372
* makes some more space.
374
void Filter::_enlarge_primitive_table() {
375
FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2];
376
for (int i = 0 ; i < _primitive_count ; i++) {
377
new_tbl[i] = _primitive[i];
379
_primitive_table_size *= 2;
380
for (int i = _primitive_count ; i < _primitive_table_size ; i++) {
383
if(_primitive != NULL) {
388
_primitive = new_tbl;
391
334
int Filter::add_primitive(FilterPrimitiveType type)
393
336
_create_constructor_table();
398
341
if (!_constructor[type]) return -1;
399
342
FilterPrimitive *created = _constructor[type]();
401
// If there is no space for new filter primitive, enlarge the table
402
if (_primitive_count >= _primitive_table_size) {
403
_enlarge_primitive_table();
406
_primitive[_primitive_count] = created;
407
int handle = _primitive_count;
344
int handle = _primitive.size();
345
_primitive.push_back(created);
416
353
// Check that target is valid primitive inside this filter
417
354
if (target < 0) return -1;
418
if (target >= _primitive_count) return -1;
419
if (!_primitive[target]) return -1;
355
if (static_cast<unsigned>(target) >= _primitive.size()) return -1;
421
357
// Check that we can create a new filter of specified type
422
358
if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE)
424
360
if (!_constructor[type]) return -1;
425
361
FilterPrimitive *created = _constructor[type]();
427
// If there is no space for new filter primitive, enlarge the table
428
if (_primitive_count >= _primitive_table_size) {
429
_enlarge_primitive_table();
432
363
delete _primitive[target];
433
364
_primitive[target] = created;
437
368
FilterPrimitive *Filter::get_primitive(int handle) {
438
if (handle < 0 || handle >= _primitive_count) return NULL;
369
if (handle < 0 || handle >= static_cast<int>(_primitive.size())) return NULL;
439
370
return _primitive[handle];
442
373
void Filter::clear_primitives()
444
for (int i = 0 ; i < _primitive_count ; i++) {
445
if (_primitive[i]) delete _primitive[i];
375
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
376
delete _primitive[i];
447
_primitive_count = 0;
450
381
void Filter::set_x(SVGLength const &length)
510
441
std::pair<double,double> Filter::_filter_resolution(
511
Geom::Rect const &area, Geom::Matrix const &trans,
442
Geom::Rect const &area, Geom::Affine const &trans,
512
443
FilterQuality const filterquality) const
514
445
std::pair<double,double> resolution;