1 /** \file
2 * Superclass for all the filter primitives
3 *
4 */
5 /*
6 * Authors:
7 * Kees Cook <kees@outflux.net>
8 * Niko Kiirala <niko@kiirala.com>
9 * Abhishek Sharma
10 *
11 * Copyright (C) 2004-2007 Authors
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #include <string.h>
22 #include "attributes.h"
23 #include "sp-filter-primitive.h"
24 #include "xml/repr.h"
25 #include "sp-filter.h"
26 #include "display/nr-filter-primitive.h"
27 #include "display/nr-filter-types.h"
29 /* FilterPrimitive base class */
31 static void sp_filter_primitive_class_init(SPFilterPrimitiveClass *klass);
32 static void sp_filter_primitive_init(SPFilterPrimitive *filter_primitive);
34 static void sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
35 static void sp_filter_primitive_release(SPObject *object);
36 static void sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value);
37 static void sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags);
38 static Inkscape::XML::Node *sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
40 static SPObjectClass *filter_primitive_parent_class;
42 GType
43 sp_filter_primitive_get_type()
44 {
45 static GType filter_primitive_type = 0;
47 if (!filter_primitive_type) {
48 GTypeInfo filter_primitive_info = {
49 sizeof(SPFilterPrimitiveClass),
50 NULL, NULL,
51 (GClassInitFunc) sp_filter_primitive_class_init,
52 NULL, NULL,
53 sizeof(SPFilterPrimitive),
54 16,
55 (GInstanceInitFunc) sp_filter_primitive_init,
56 NULL, /* value_table */
57 };
58 filter_primitive_type = g_type_register_static(SP_TYPE_OBJECT, "SPFilterPrimitive", &filter_primitive_info, (GTypeFlags)0);
59 }
60 return filter_primitive_type;
61 }
63 static void
64 sp_filter_primitive_class_init(SPFilterPrimitiveClass *klass)
65 {
66 //GObjectClass *gobject_class = (GObjectClass *)klass;
67 SPObjectClass *sp_object_class = (SPObjectClass *)klass;
69 filter_primitive_parent_class = (SPObjectClass*)g_type_class_peek_parent(klass);
71 sp_object_class->build = sp_filter_primitive_build;
72 sp_object_class->release = sp_filter_primitive_release;
73 sp_object_class->write = sp_filter_primitive_write;
74 sp_object_class->set = sp_filter_primitive_set;
75 sp_object_class->update = sp_filter_primitive_update;
77 /* This should never be called on this base class, but only on derived
78 * classes. */
79 klass->build_renderer = NULL;
80 }
82 static void
83 sp_filter_primitive_init(SPFilterPrimitive *filter_primitive)
84 {
85 filter_primitive->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
86 filter_primitive->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
87 }
89 /**
90 * Reads the Inkscape::XML::Node, and initializes SPFilterPrimitive variables. For this to get called,
91 * our name must be associated with a repr via "sp_object_type_register". Best done through
92 * sp-object-repr.cpp's repr_name_entries array.
93 */
94 static void
95 sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
96 {
97 if (((SPObjectClass *) filter_primitive_parent_class)->build) {
98 ((SPObjectClass *) filter_primitive_parent_class)->build(object, document, repr);
99 }
101 object->readAttr( "in" );
102 object->readAttr( "result" );
103 }
105 /**
106 * Drops any allocated memory.
107 */
108 static void
109 sp_filter_primitive_release(SPObject *object)
110 {
111 /* deal with our children and our selves here */
112 if (((SPObjectClass *) filter_primitive_parent_class)->release)
113 ((SPObjectClass *) filter_primitive_parent_class)->release(object);
114 }
116 /**
117 * Sets a specific value in the SPFilterPrimitive.
118 */
119 static void
120 sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value)
121 {
122 SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object);
123 (void)filter_primitive;
125 int image_nr;
126 switch (key) {
127 case SP_ATTR_IN:
128 if (value) {
129 image_nr = sp_filter_primitive_read_in(filter_primitive, value);
130 } else {
131 image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
132 }
133 if (image_nr != filter_primitive->image_in) {
134 filter_primitive->image_in = image_nr;
135 object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
136 }
137 break;
138 case SP_ATTR_RESULT:
139 if (value) {
140 image_nr = sp_filter_primitive_read_result(filter_primitive, value);
141 } else {
142 image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
143 }
144 if (image_nr != filter_primitive->image_out) {
145 filter_primitive->image_out = image_nr;
146 object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
147 }
148 break;
149 }
151 /* See if any parents need this value. */
152 if (((SPObjectClass *) filter_primitive_parent_class)->set) {
153 ((SPObjectClass *) filter_primitive_parent_class)->set(object, key, value);
154 }
155 }
157 /**
158 * Receives update notifications.
159 */
160 static void
161 sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags)
162 {
163 //SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object);
165 if (flags & SP_OBJECT_MODIFIED_FLAG) {
166 object->readAttr( "in" );
167 object->readAttr( "result" );
168 }
170 if (((SPObjectClass *) filter_primitive_parent_class)->update) {
171 ((SPObjectClass *) filter_primitive_parent_class)->update(object, ctx, flags);
172 }
173 }
175 /**
176 * Writes its settings to an incoming repr object, if any.
177 */
178 static Inkscape::XML::Node *
179 sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags)
180 {
181 SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(object);
182 SPFilter *parent = SP_FILTER(object->parent);
184 if (!repr) {
185 repr = SP_OBJECT_REPR(object)->duplicate(doc);
186 }
188 gchar const *in_name = sp_filter_name_for_image(parent, prim->image_in);
189 repr->setAttribute("in", in_name);
191 gchar const *out_name = sp_filter_name_for_image(parent, prim->image_out);
192 repr->setAttribute("result", out_name);
194 if (((SPObjectClass *) filter_primitive_parent_class)->write) {
195 ((SPObjectClass *) filter_primitive_parent_class)->write(object, doc, repr, flags);
196 }
198 return repr;
199 }
201 int sp_filter_primitive_read_in(SPFilterPrimitive *prim, gchar const *name)
202 {
203 if (!name) return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
204 // TODO: are these case sensitive or not? (assumed yes)
205 switch (name[0]) {
206 case 'S':
207 if (strcmp(name, "SourceGraphic") == 0)
208 return Inkscape::Filters::NR_FILTER_SOURCEGRAPHIC;
209 if (strcmp(name, "SourceAlpha") == 0)
210 return Inkscape::Filters::NR_FILTER_SOURCEALPHA;
211 if (strcmp(name, "StrokePaint") == 0)
212 return Inkscape::Filters::NR_FILTER_STROKEPAINT;
213 break;
214 case 'B':
215 if (strcmp(name, "BackgroundImage") == 0)
216 return Inkscape::Filters::NR_FILTER_BACKGROUNDIMAGE;
217 if (strcmp(name, "BackgroundAlpha") == 0)
218 return Inkscape::Filters::NR_FILTER_BACKGROUNDALPHA;
219 break;
220 case 'F':
221 if (strcmp(name, "FillPaint") == 0)
222 return Inkscape::Filters::NR_FILTER_FILLPAINT;
223 break;
224 }
226 SPFilter *parent = SP_FILTER(prim->parent);
227 int ret = sp_filter_get_image_name(parent, name);
228 if (ret >= 0) return ret;
230 return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
231 }
233 int sp_filter_primitive_read_result(SPFilterPrimitive *prim, gchar const *name)
234 {
235 SPFilter *parent = SP_FILTER(prim->parent);
236 int ret = sp_filter_get_image_name(parent, name);
237 if (ret >= 0) return ret;
239 ret = sp_filter_set_image_name(parent, name);
240 if (ret >= 0) return ret;
242 return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
243 }
245 /**
246 * Gives name for output of previous filter. Makes things clearer when prim
247 * is a filter with two or more inputs. Returns the slot number of result
248 * of previous primitive, or NR_FILTER_SOURCEGRAPHIC if this is the first
249 * primitive.
250 */
251 int sp_filter_primitive_name_previous_out(SPFilterPrimitive *prim) {
252 SPFilter *parent = SP_FILTER(prim->parent);
253 SPObject *i = parent->children;
254 while (i && i->next != prim) i = i->next;
255 if (i) {
256 SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
257 if (i_prim->image_out < 0) {
258 Glib::ustring name = sp_filter_get_new_result_name(parent);
259 int slot = sp_filter_set_image_name(parent, name.c_str());
260 i_prim->image_out = slot;
261 //XML Tree is being directly used while it shouldn't be.
262 i_prim->getRepr()->setAttribute("result", name.c_str());
263 return slot;
264 } else {
265 return i_prim->image_out;
266 }
267 }
268 return Inkscape::Filters::NR_FILTER_SOURCEGRAPHIC;
269 }
271 /* Common initialization for filter primitives */
272 void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::Filters::FilterPrimitive *nr_prim)
273 {
274 g_assert(sp_prim != NULL);
275 g_assert(nr_prim != NULL);
278 nr_prim->set_input(sp_prim->image_in);
279 nr_prim->set_output(sp_prim->image_out);
281 /* TODO: place here code to handle input images, filter area etc. */
282 }
286 /*
287 Local Variables:
288 mode:c++
289 c-file-style:"stroustrup"
290 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
291 indent-tabs-mode:nil
292 fill-column:99
293 End:
294 */
295 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :