Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
nr-filter-slot.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * A container class for filter slots. Allows for simple getting and
4 * setting images in filter slots without having to bother with
5 * table indexes and such.
6 *
7 * Author:
8 * Niko Kiirala <niko@kiirala.com>
9 *
10 * Copyright (C) 2006,2007 Niko Kiirala
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include <cassert>
16#include <cstring>
17
18#include <2geom/transforms.h>
19#include "cairo-utils.h"
20#include "drawing-context.h"
21#include "drawing-surface.h"
22#include "nr-filter-types.h"
23#include "nr-filter-gaussian.h"
24#include "nr-filter-slot.h"
25#include "nr-filter-units.h"
26
27namespace Inkscape {
28namespace Filters {
29
30FilterSlot::FilterSlot(DrawingContext *bgdc, DrawingContext &graphic, FilterUnits const &units, RenderContext &rc, int blurquality)
31 : _source_graphic(graphic.rawTarget())
32 , _background_ct(bgdc ? bgdc->raw() : nullptr)
33 , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme
34 , _background_area(bgdc ? bgdc->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme
35 , _units(units)
36 , _last_out(NR_FILTER_SOURCEGRAPHIC)
37 , _blurquality(blurquality)
38 , rc(rc)
39 , device_scale(graphic.surface()->device_scale())
40{
41 using Geom::X;
42 using Geom::Y;
43
44 // compute slot bbox
46 Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans;
47 Geom::Point min = bbox_trans.min();
48 _slot_x = min[X];
49 _slot_y = min[Y];
50
51 if (trans.isTranslation()) {
54 } else {
55 _slot_w = std::ceil(bbox_trans.width());
56 _slot_h = std::ceil(bbox_trans.height());
57 }
58}
59
61{
62 for (auto &_slot : _slots) {
63 cairo_surface_destroy(_slot.second);
64 }
65}
66
68{
69 if (slot_nr == NR_FILTER_SLOT_NOT_SET)
70 slot_nr = _last_out;
71
72 SlotMap::iterator s = _slots.find(slot_nr);
73
74 /* If we didn't have the specified image, but we could create it
75 * from the other information we have, let's do that */
76 if (s == _slots.end()
77 && (slot_nr == NR_FILTER_SOURCEGRAPHIC
78 || slot_nr == NR_FILTER_SOURCEALPHA
79 || slot_nr == NR_FILTER_BACKGROUNDIMAGE
80 || slot_nr == NR_FILTER_BACKGROUNDALPHA
81 || slot_nr == NR_FILTER_FILLPAINT
82 || slot_nr == NR_FILTER_STROKEPAINT))
83 {
84 switch (slot_nr) {
87 // Assume all source graphics are sRGB
90 cairo_surface_destroy(tr);
91 } break;
94 // Assume all backgrounds are sRGB
97 cairo_surface_destroy(bg);
98 } break;
103 cairo_surface_destroy(alpha);
104 } break;
109 cairo_surface_destroy(ba);
110 } break;
111 case NR_FILTER_FILLPAINT: //TODO
112 case NR_FILTER_STROKEPAINT: //TODO
113 default:
114 break;
115 }
116 s = _slots.find(slot_nr);
117 }
118
119 if (s == _slots.end()) {
120 // create empty surface
121 cairo_surface_t *empty = cairo_surface_create_similar(
122 _source_graphic, cairo_surface_get_content(_source_graphic),
124 _set_internal(slot_nr, empty);
125 cairo_surface_destroy(empty);
126 s = _slots.find(slot_nr);
127 }
128
129 if (s->second && cairo_surface_status(s->second) == CAIRO_STATUS_NO_MEMORY) {
130 // Simulate Cairomm behaviour by throwing std::bad_alloc.
131 throw std::bad_alloc();
132 }
133
134 return s->second;
135}
136
138{
140
141 if (trans.isTranslation()) {
142 cairo_surface_reference(_source_graphic);
143 return _source_graphic;
144 }
145
146 cairo_surface_t *tsg = cairo_surface_create_similar(
147 _source_graphic, cairo_surface_get_content(_source_graphic),
149 cairo_t *tsg_ct = cairo_create(tsg);
150
151 cairo_translate(tsg_ct, -_slot_x, -_slot_y);
152 ink_cairo_transform(tsg_ct, trans);
153 cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top());
154 cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0);
155 cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE);
156 cairo_paint(tsg_ct);
157 cairo_destroy(tsg_ct);
158
159 return tsg;
160}
161
163{
165
166 cairo_surface_t *tbg;
167
168 if (_background_ct) {
169 cairo_surface_t *bg = cairo_get_group_target(_background_ct);
170 tbg = cairo_surface_create_similar(
171 bg, cairo_surface_get_content(bg),
173 cairo_t *tbg_ct = cairo_create(tbg);
174
175 cairo_translate(tbg_ct, -_slot_x, -_slot_y);
176 ink_cairo_transform(tbg_ct, trans);
177 cairo_translate(tbg_ct, _background_area.left(), _background_area.top());
178 cairo_set_source_surface(tbg_ct, bg, 0, 0);
179 cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE);
180 cairo_paint(tbg_ct);
181 cairo_destroy(tbg_ct);
182 } else {
183 tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w * device_scale, _slot_h * device_scale);
184 }
185
186 return tbg;
187}
188
190{
192
194 if (trans.isIdentity()) {
195 cairo_surface_reference(result);
196 return result;
197 }
198
199 cairo_surface_t *r = cairo_surface_create_similar(_source_graphic,
200 cairo_surface_get_content(_source_graphic),
204 cairo_t *r_ct = cairo_create(r);
205
206 cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top());
207 ink_cairo_transform(r_ct, trans);
208 cairo_translate(r_ct, _slot_x, _slot_y);
209 cairo_set_source_surface(r_ct, result, 0, 0);
210 cairo_set_operator(r_ct, CAIRO_OPERATOR_SOURCE);
211 cairo_paint(r_ct);
212 cairo_destroy(r_ct);
213
214 return r;
215}
216
218{
219 // destroy after referencing
220 // this way assigning a surface to a slot it already occupies will not cause errors
221 cairo_surface_reference(surface);
222
223 SlotMap::iterator s = _slots.find(slot_nr);
224 if (s != _slots.end()) {
225 cairo_surface_destroy(s->second);
226 }
227
228 _slots[slot_nr] = surface;
229}
230
232{
233 g_return_if_fail(surface != nullptr);
234
235 if (slot_nr == NR_FILTER_SLOT_NOT_SET)
236 slot_nr = NR_FILTER_UNNAMED_SLOT;
237
238 _set_internal(slot_nr, surface);
239 _last_out = slot_nr;
240}
241
243{
244 if (slot_nr == NR_FILTER_SLOT_NOT_SET)
245 slot_nr = NR_FILTER_UNNAMED_SLOT;
246
247 _primitiveAreas[slot_nr] = area;
248}
249
251{
252 if (slot_nr == NR_FILTER_SLOT_NOT_SET)
253 slot_nr = _last_out;
254
255 auto s = _primitiveAreas.find(slot_nr);
256
257 if (s == _primitiveAreas.end()) {
258 return *_units.get_filter_area();
259 }
260 return s->second;
261}
262
267
268} // namespace Filters
269} // namespace Inkscape
270
271/*
272 Local Variables:
273 mode:c++
274 c-file-style:"stroustrup"
275 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
276 indent-tabs-mode:nil
277 fill-column:99
278 End:
279*/
280// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out)
cairo_surface_t * ink_cairo_extract_alpha(cairo_surface_t *s)
Extract the alpha channel into a new surface.
void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m)
void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci)
Set the color_interpolation_value for a Cairo surface.
Cairo integration helpers.
Cairo::RefPtr< Cairo::ImageSurface > surface
Definition canvas.cpp:137
3x3 matrix representing an affine transformation.
Definition affine.h:70
bool isIdentity(Coord eps=EPSILON) const
Check whether this matrix is an identity matrix.
Definition affine.cpp:109
bool isTranslation(Coord eps=EPSILON) const
Check whether this matrix represents a pure translation.
Definition affine.cpp:123
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Minimal wrapper over Cairo.
Geom::Rect targetLogicalBounds() const
void _set_internal(int slot, cairo_surface_t *s)
void set_primitive_area(int slot, Geom::Rect &area)
cairo_surface_t * getcairo(int slot)
Returns the pixblock in specified slot.
cairo_surface_t * _get_transformed_source_graphic() const
void set(int slot, cairo_surface_t *s)
Sets or re-sets the pixblock associated with given slot.
FilterSlot(DrawingContext *bgdc, DrawingContext &graphic, FilterUnits const &units, RenderContext &rc, int blurquality)
Creates a new FilterSlot object.
cairo_surface_t * get_result(int slot_nr)
cairo_surface_t * _get_transformed_background() const
~FilterSlot()
Destroys the FilterSlot object and all its contents.
Geom::Rect get_primitive_area(int slot) const
Geom::IntRect _background_area
needed to extract background
cairo_surface_t * _source_graphic
Geom::Affine get_matrix_display2pb() const
Gets the display coordinates to pixblock coordinates transformation matrix.
Geom::Affine get_matrix_pb2display() const
Gets the pixblock coordinates to display coordinates transformation matrix.
Geom::OptRect get_filter_area() const
Gets the filter effects area in user coordinates.
RectangularCluster rc
Css & result
Cairo drawing context with Inkscape extensions.
Cairo surface that remembers its origin.
struct _cairo_surface cairo_surface_t
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Various utility functions.
Definition affine.h:22
Helper class to stream background task notifications as a series of messages.
TODO: insert short description here.
struct _cairo cairo_t
Definition path-cairo.h:16
@ SP_CSS_COLOR_INTERPOLATION_SRGB
Affine transformation classes.