1 /* This file is part of GEGL
2 *
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
7 *
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2003 Calvin Williamson
17 * 2006 Øyvind Kolås
18 * 2013 Daniel Sabo
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <glib-object.h>
26 #include <gobject/gvaluecollector.h>
27
28 #include "gegl-types-internal.h"
29
30 #include "gegl.h"
31 #include "gegl-debug.h"
32 #include "gegl-node-private.h"
33 #include "gegl-connection.h"
34 #include "gegl-pad.h"
35 #include "gegl-visitable.h"
36 #include "gegl-config.h"
37
38 #include "gegl-region.h"
39
40 #include "graph/gegl-visitor.h"
41 #include "graph/gegl-callback-visitor.h"
42 #include "graph/gegl-node-output-visitable.h"
43
44 #include "operation/gegl-operation.h"
45 #include "operation/gegl-operation-private.h"
46 #include "operation/gegl-operation-context-private.h"
47 #include "operation/gegl-operations.h"
48 #include "operation/gegl-operation-meta.h"
49
50 #include "process/gegl-eval-manager.h"
51
52 enum
53 {
54 PROP_0,
55 PROP_OP_CLASS,
56 PROP_OPERATION,
57 PROP_NAME,
58 PROP_DONT_CACHE,
59 PROP_CACHE_POLICY,
60 PROP_USE_OPENCL,
61 PROP_PASSTHROUGH
62 };
63
64 enum
65 {
66 INVALIDATED,
67 COMPUTED,
68 PROGRESS,
69 LAST_SIGNAL
70 };
71
72
73 struct _GeglNodePrivate
74 {
75 GSList *source_connections;
76 GSList *sink_connections;
77 GSList *children; /* used for children */
78 GeglNode *parent;
79 gchar *name;
80 gchar *debug_name;
81 GeglEvalManager *eval_manager;
82 };
83
84
85 static guint gegl_node_signals[LAST_SIGNAL] = {0};
86
87
88 static void gegl_node_class_init (GeglNodeClass *klass);
89 static void gegl_node_init (GeglNode *self);
90 static void gegl_node_finalize (GObject *self_object);
91 static void gegl_node_dispose (GObject *self_object);
92 static void gegl_node_local_set_property (GObject *gobject,
93 guint prop_id,
94 const GValue *value,
95 GParamSpec *pspec);
96 static void gegl_node_local_get_property (GObject *gobject,
97 guint prop_id,
98 GValue *value,
99 GParamSpec *pspec);
100 static gboolean gegl_node_pads_exist (GeglNode *sink,
101 const gchar *sink_pad_name,
102 GeglNode *source,
103 const gchar *source_pad_name);
104 static GeglConnection *gegl_node_find_connection (GeglNode *sink,
105 GeglPad *sink_pad);
106 static void gegl_node_visitable_iface_init (gpointer ginterface,
107 gpointer interface_data);
108 static gboolean gegl_node_visitable_accept (GeglVisitable *visitable,
109 GeglVisitor *visitor);
110 static GSList* gegl_node_visitable_depends_on (GeglVisitable *visitable);
111 static void gegl_node_set_operation_object (GeglNode *self,
112 GeglOperation *operation);
113 static void gegl_node_set_op_class (GeglNode *self,
114 const gchar *op_class,
115 const gchar *first_property,
116 va_list var_args);
117 static void gegl_node_disconnect_sinks (GeglNode *self);
118 static void gegl_node_disconnect_sources (GeglNode *self);
119 static void gegl_node_property_changed (GObject *gobject,
120 GParamSpec *arg1,
121 gpointer user_data);
122
123 static void gegl_node_update_debug_name (GeglNode *node);
124
125
G_DEFINE_TYPE_WITH_CODE(GeglNode,gegl_node,G_TYPE_OBJECT,G_ADD_PRIVATE (GeglNode)G_IMPLEMENT_INTERFACE (GEGL_TYPE_VISITABLE,gegl_node_visitable_iface_init))126 G_DEFINE_TYPE_WITH_CODE (GeglNode, gegl_node, G_TYPE_OBJECT,
127 G_ADD_PRIVATE (GeglNode)
128 G_IMPLEMENT_INTERFACE (GEGL_TYPE_VISITABLE,
129 gegl_node_visitable_iface_init))
130
131
132 static void
133 gegl_node_class_init (GeglNodeClass *klass)
134 {
135 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
136
137 gobject_class->finalize = gegl_node_finalize;
138 gobject_class->dispose = gegl_node_dispose;
139 gobject_class->set_property = gegl_node_local_set_property;
140 gobject_class->get_property = gegl_node_local_get_property;
141
142 g_object_class_install_property (gobject_class, PROP_OPERATION,
143 g_param_spec_object ("gegl-operation",
144 "Operation Object",
145 "The associated GeglOperation instance",
146 GEGL_TYPE_OPERATION,
147 G_PARAM_READWRITE |
148 G_PARAM_STATIC_STRINGS |
149 G_PARAM_CONSTRUCT));
150
151 g_object_class_install_property (gobject_class, PROP_OP_CLASS,
152 g_param_spec_string ("operation",
153 "Operation Type",
154 "The type of associated GeglOperation",
155 "",
156 G_PARAM_CONSTRUCT |
157 G_PARAM_STATIC_STRINGS |
158 G_PARAM_READWRITE));
159
160 g_object_class_install_property (gobject_class, PROP_DONT_CACHE,
161 g_param_spec_boolean ("dont-cache",
162 "Do not cache",
163 "Do not cache the result of this operation, the property is inherited by children created from a node."
164 " (Deprecated for \"cache-policy\".)",
165 FALSE,
166 G_PARAM_CONSTRUCT |
167 G_PARAM_STATIC_STRINGS |
168 G_PARAM_READWRITE));
169
170 g_object_class_install_property (gobject_class, PROP_CACHE_POLICY,
171 g_param_spec_enum ("cache-policy",
172 "Cache Policy",
173 "Cache policy for this node, the property is inherited by children created from a node.",
174 GEGL_TYPE_CACHE_POLICY,
175 GEGL_CACHE_POLICY_AUTO,
176 G_PARAM_CONSTRUCT |
177 G_PARAM_STATIC_STRINGS |
178 G_PARAM_READWRITE));
179
180 g_object_class_install_property (gobject_class, PROP_USE_OPENCL,
181 g_param_spec_boolean ("use-opencl",
182 "Use OpenCL",
183 "Use the OpenCL version of this operation if available, this property is inherited by children created from a node.",
184 TRUE,
185 G_PARAM_CONSTRUCT |
186 G_PARAM_STATIC_STRINGS |
187 G_PARAM_READWRITE));
188
189
190 g_object_class_install_property (gobject_class, PROP_NAME,
191 g_param_spec_string ("name",
192 "Name",
193 "The name of the node",
194 "",
195 G_PARAM_CONSTRUCT |
196 G_PARAM_STATIC_STRINGS |
197 G_PARAM_READWRITE));
198
199 g_object_class_install_property (gobject_class, PROP_PASSTHROUGH,
200 g_param_spec_boolean ("passthrough",
201 "Passthrough",
202 "Act as a nop, passing input unmodifed through to ouput.",
203 FALSE,
204 G_PARAM_CONSTRUCT |
205 G_PARAM_STATIC_STRINGS |
206 G_PARAM_READWRITE));
207
208 gegl_node_signals[INVALIDATED] =
209 g_signal_new ("invalidated",
210 G_TYPE_FROM_CLASS (klass),
211 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
212 0, NULL, NULL, NULL,
213 G_TYPE_NONE, 1,
214 GEGL_TYPE_RECTANGLE);
215
216 gegl_node_signals[COMPUTED] =
217 g_signal_new ("computed",
218 G_TYPE_FROM_CLASS (klass),
219 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
220 0, NULL, NULL, NULL,
221 G_TYPE_NONE, 1,
222 GEGL_TYPE_RECTANGLE);
223
224 gegl_node_signals[PROGRESS] =
225 g_signal_new ("progress",
226 G_TYPE_FROM_CLASS (klass),
227 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
228 0, NULL, NULL, NULL,
229 G_TYPE_NONE, 1, G_TYPE_DOUBLE);
230 }
231
232 static void
gegl_node_init(GeglNode * self)233 gegl_node_init (GeglNode *self)
234 {
235 self->priv = gegl_node_get_instance_private (self);
236
237 self->pads = NULL;
238 self->input_pads = NULL;
239 self->output_pads = NULL;
240 self->operation = NULL;
241 self->is_graph = FALSE;
242 self->cache = NULL;
243 self->output_visitable = gegl_node_output_visitable_new (self);
244 g_mutex_init (&self->mutex);
245
246 }
247
248 static void
gegl_node_visitable_iface_init(gpointer ginterface,gpointer interface_data)249 gegl_node_visitable_iface_init (gpointer ginterface,
250 gpointer interface_data)
251 {
252 GeglVisitableClass *visitable_class = ginterface;
253
254 visitable_class->accept = gegl_node_visitable_accept;
255 visitable_class->depends_on = gegl_node_visitable_depends_on;
256 }
257
258 static void
gegl_node_dispose(GObject * gobject)259 gegl_node_dispose (GObject *gobject)
260 {
261 GeglNode *self = GEGL_NODE (gobject);
262
263 if (self->priv->parent != NULL)
264 {
265 GeglNode *parent = self->priv->parent;
266 self->priv->parent = NULL;
267 gegl_node_remove_child (parent, self);
268 }
269
270 gegl_node_remove_children (self);
271 g_clear_object (&self->cache);
272 g_clear_object (&self->priv->eval_manager);
273
274 G_OBJECT_CLASS (gegl_node_parent_class)->dispose (gobject);
275 }
276
277 static void
gegl_node_finalize(GObject * gobject)278 gegl_node_finalize (GObject *gobject)
279 {
280 GeglNode *self = GEGL_NODE (gobject);
281
282 gegl_node_disconnect_sources (self);
283 gegl_node_disconnect_sinks (self);
284
285 g_slist_free_full (self->pads, g_object_unref);
286 g_slist_free (self->input_pads);
287 g_slist_free (self->output_pads);
288
289 g_clear_object (&self->operation);
290 g_clear_object (&self->output_visitable);
291 g_free (self->priv->name);
292 g_free (self->priv->debug_name);
293
294 g_mutex_clear (&self->mutex);
295
296 G_OBJECT_CLASS (gegl_node_parent_class)->finalize (gobject);
297 }
298
299 static void
gegl_node_local_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)300 gegl_node_local_set_property (GObject *gobject,
301 guint property_id,
302 const GValue *value,
303 GParamSpec *pspec)
304 {
305 GeglNode *node = GEGL_NODE (gobject);
306
307 switch (property_id)
308 {
309 case PROP_NAME:
310 gegl_node_set_name (node, g_value_get_string (value));
311 break;
312
313 case PROP_DONT_CACHE:
314 node->dont_cache = g_value_get_boolean (value);
315 break;
316
317 case PROP_CACHE_POLICY:
318 node->cache_policy = g_value_get_enum (value);
319 break;
320
321 case PROP_PASSTHROUGH:
322 node->passthrough = g_value_get_boolean (value);
323 break;
324
325 case PROP_USE_OPENCL:
326 node->use_opencl = g_value_get_boolean (value);
327 break;
328
329 case PROP_OP_CLASS:
330 {
331 va_list null; /* dummy to pass along, it's not used anyways since
332 * the preceding argument is NULL, gcc might warn about
333 * use of uninitialized variable.
334 */
335 #if defined(__GNUC__)
336 memset(&null, 0, sizeof(null));
337 #endif
338 gegl_node_set_op_class (node, g_value_get_string (value), NULL, null);
339 }
340 break;
341
342 case PROP_OPERATION:
343 gegl_node_set_operation_object (node, g_value_get_object (value));
344 break;
345
346 default:
347 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
348 break;
349 }
350 }
351
352 static void
gegl_node_local_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)353 gegl_node_local_get_property (GObject *gobject,
354 guint property_id,
355 GValue *value,
356 GParamSpec *pspec)
357 {
358 GeglNode *node = GEGL_NODE (gobject);
359
360 switch (property_id)
361 {
362 case PROP_OP_CLASS:
363 if (node->operation)
364 g_value_set_string (value, GEGL_OPERATION_GET_CLASS (node->operation)->name);
365 break;
366
367 case PROP_DONT_CACHE:
368 g_value_set_boolean (value, node->dont_cache);
369 break;
370
371 case PROP_CACHE_POLICY:
372 g_value_set_enum (value, node->cache_policy);
373 break;
374
375 case PROP_PASSTHROUGH:
376 g_value_set_boolean (value, node->passthrough);
377 break;
378
379 case PROP_USE_OPENCL:
380 g_value_set_boolean (value, node->use_opencl);
381 break;
382
383 case PROP_NAME:
384 g_value_set_string (value, gegl_node_get_name (node));
385 break;
386
387 case PROP_OPERATION:
388 g_value_set_object (value, node->operation);
389 break;
390
391 default:
392 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
393 break;
394 }
395 }
396
397 /**
398 * gegl_node_get_pad:
399 * @self: a #GeglNode.
400 * @name: property name.
401 *
402 * Get a property.
403 *
404 * Returns: A #GeglPad.
405 **/
406 GeglPad *
gegl_node_get_pad(GeglNode * self,const gchar * name)407 gegl_node_get_pad (GeglNode *self,
408 const gchar *name)
409 {
410 GSList *list;
411
412 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
413 g_return_val_if_fail (name != NULL, NULL);
414
415 if (!self->pads)
416 return NULL;
417
418 for (list = self->pads; list; list = g_slist_next (list))
419 {
420 GeglPad *property = list->data;
421
422 if (!strcmp (name, gegl_pad_get_name (property)))
423 return property;
424 }
425
426 return NULL;
427 }
428
429 gboolean
gegl_node_has_pad(GeglNode * self,const gchar * name)430 gegl_node_has_pad (GeglNode *self,
431 const gchar *name)
432 {
433 return gegl_node_get_pad (self, name) != NULL;
434 }
435
436 static inline gchar **
_make_pad_list(GSList * iter)437 _make_pad_list (GSList *iter)
438 {
439 gchar **list;
440 gint i;
441
442 if (!iter)
443 return NULL;
444
445 list = g_new0 (gchar *, g_slist_length (iter) + 1);
446
447 for (i = 0; iter; iter = iter->next, i++)
448 {
449 GeglPad *pad = iter->data;
450 list[i] = g_strdup (pad->name);
451 }
452
453 return list;
454 }
455
456 gchar **
gegl_node_list_input_pads(GeglNode * self)457 gegl_node_list_input_pads (GeglNode *self)
458 {
459 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
460
461 return _make_pad_list (self->input_pads);
462 }
463
464 gchar **
gegl_node_list_output_pads(GeglNode * self)465 gegl_node_list_output_pads (GeglNode *self)
466 {
467 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
468
469 return _make_pad_list (self->output_pads);
470 }
471
472 /**
473 * gegl_node_get_pads:
474 * @self: a #GeglNode.
475 *
476 * Returns: A list of #GeglPad.
477 **/
478 GSList *
gegl_node_get_pads(GeglNode * self)479 gegl_node_get_pads (GeglNode *self)
480 {
481 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
482
483 return self->pads;
484 }
485
486 /**
487 * gegl_node_get_input_pads:
488 * @self: a #GeglNode.
489 *
490 * Returns: A list of #GeglPad.
491 **/
492 GSList *
gegl_node_get_input_pads(GeglNode * self)493 gegl_node_get_input_pads (GeglNode *self)
494 {
495 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
496
497 return self->input_pads;
498 }
499
500 void
gegl_node_add_pad(GeglNode * self,GeglPad * pad)501 gegl_node_add_pad (GeglNode *self,
502 GeglPad *pad)
503 {
504 g_return_if_fail (GEGL_IS_NODE (self));
505 g_return_if_fail (GEGL_IS_PAD (pad));
506
507 if (gegl_node_get_pad (self, gegl_pad_get_name (pad)))
508 return;
509
510 self->pads = g_slist_prepend (self->pads, pad);
511
512 if (gegl_pad_is_output (pad))
513 self->output_pads = g_slist_prepend (self->output_pads, pad);
514
515 if (gegl_pad_is_input (pad))
516 self->input_pads = g_slist_prepend (self->input_pads, pad);
517 }
518
519 void
gegl_node_remove_pad(GeglNode * self,GeglPad * pad)520 gegl_node_remove_pad (GeglNode *self,
521 GeglPad *pad)
522 {
523 GeglNode *pad_node;
524
525 g_return_if_fail (GEGL_IS_NODE (self));
526 g_return_if_fail (GEGL_IS_PAD (pad));
527
528 self->pads = g_slist_remove (self->pads, pad);
529
530 if (gegl_pad_is_output (pad))
531 self->output_pads = g_slist_remove (self->output_pads, pad);
532
533 if (gegl_pad_is_input (pad))
534 self->input_pads = g_slist_remove (self->input_pads, pad);
535
536 pad_node = gegl_pad_get_node (pad);
537
538 /* This was a proxy pad, also remove the nop node */
539 if (self != pad_node)
540 gegl_node_remove_child (self, pad_node);
541
542 g_object_unref (pad);
543 }
544
545 static gboolean
gegl_node_pads_exist(GeglNode * sink,const gchar * sink_pad_name,GeglNode * source,const gchar * source_pad_name)546 gegl_node_pads_exist (GeglNode *sink,
547 const gchar *sink_pad_name,
548 GeglNode *source,
549 const gchar *source_pad_name)
550 {
551 GeglPad *sink_pad;
552
553 GeglPad *source_pad;
554
555 if (sink)
556 {
557 g_assert (sink_pad_name);
558 sink_pad = gegl_node_get_pad (sink, sink_pad_name);
559 if (!sink_pad || !gegl_pad_is_input (sink_pad))
560 {
561 g_warning ("%s: Can't find sink property %s of %s", G_STRFUNC,
562 sink_pad_name, gegl_node_get_debug_name (sink));
563 return FALSE;
564 }
565 }
566
567 if (source)
568 {
569 g_assert (source_pad_name);
570 source_pad = gegl_node_get_pad (source, source_pad_name);
571 if (!source_pad || !gegl_pad_is_output (source_pad))
572 {
573 g_warning ("%s: Can't find source property %s of %s", G_STRFUNC,
574 source_pad_name, gegl_node_get_debug_name (source));
575 return FALSE;
576 }
577 }
578
579 return TRUE;
580 }
581
582 static GeglConnection *
gegl_node_find_connection(GeglNode * sink,GeglPad * sink_pad)583 gegl_node_find_connection (GeglNode *sink,
584 GeglPad *sink_pad)
585 {
586 GSList *list;
587
588 g_return_val_if_fail (GEGL_IS_NODE (sink), NULL);
589
590 for (list = sink->priv->source_connections; list; list = g_slist_next (list))
591 {
592 GeglConnection *connection = list->data;
593
594 if (sink_pad == gegl_connection_get_sink_pad (connection))
595 return connection;
596 }
597
598 return NULL;
599 }
600
601 gboolean
gegl_node_connect_to(GeglNode * source,const gchar * source_pad_name,GeglNode * sink,const gchar * sink_pad_name)602 gegl_node_connect_to (GeglNode *source,
603 const gchar *source_pad_name,
604 GeglNode *sink,
605 const gchar *sink_pad_name)
606 {
607 return gegl_node_connect_from (sink, sink_pad_name, source, source_pad_name);
608 }
609
610 /* the implementation of gegl_node_invalidated() can use either GeglRegions
611 * or GeglRectangles (bounding boxes) for calculating the invalidated areas
612 * of the nodes in the graph. The GeglRegion version is more granular,
613 * invalidating exact areas, but has higher overhead, while the GeglRectangle
614 * version in more coarse, potentially over-invalidating (but never under-
615 * invalidating), but has lower overhead.
616 *
617 * TODO: decide if the higher overhead of the GeglRegion version is worth it.
618 */
619 /* #define GEGL_NODE_INVALIDATED_USE_REGIONS */
620
621 #ifdef GEGL_NODE_INVALIDATED_USE_REGIONS
622
623 static gboolean
gegl_node_invalidated_invalidate_node(GeglNode * node,gpointer data)624 gegl_node_invalidated_invalidate_node (GeglNode *node,
625 gpointer data)
626 {
627 GHashTable *regions = data;
628 GeglRegion *region = g_hash_table_lookup (regions, node);
629 GeglRectangle *rects;
630 gint n_rects;
631 GSList *iter;
632 gint i;
633
634 node->valid_have_rect = FALSE;
635
636 gegl_region_get_rectangles (region,
637 &rects, &n_rects);
638
639 for (i = 0; i < n_rects; i++)
640 {
641 if (node->cache)
642 gegl_cache_invalidate (node->cache, &rects[i]);
643
644 g_signal_emit (node, gegl_node_signals[INVALIDATED], 0,
645 &rects[i], NULL);
646 }
647
648 for (iter = node->priv->sink_connections; iter; iter = g_slist_next (iter))
649 {
650 GeglConnection *connection = iter->data;
651 GeglNode *sink_node = gegl_connection_get_sink_node (connection);
652 GeglPad *sink_pad = gegl_connection_get_sink_pad (connection);
653 GeglRegion *sink_region = g_hash_table_lookup (regions, sink_node);
654
655 if (! sink_region)
656 {
657 sink_region = gegl_region_new ();
658
659 g_hash_table_insert (regions, sink_node, sink_region);
660 }
661
662 if (sink_node->operation)
663 {
664 for (i = 0; i < n_rects; i++)
665 {
666 GeglRectangle invalidated_rect;
667
668 invalidated_rect = gegl_operation_get_invalidated_by_change (
669 sink_node->operation,
670 gegl_pad_get_name (sink_pad), &rects[i]);
671
672 gegl_region_union_with_rect (sink_region, &invalidated_rect);
673 }
674 }
675 else
676 {
677 gegl_region_union (sink_region, region);
678 }
679 }
680
681 g_free (rects);
682
683 return FALSE;
684 }
685
686 void
gegl_node_invalidated(GeglNode * node,const GeglRectangle * rect,gboolean clear_cache)687 gegl_node_invalidated (GeglNode *node,
688 const GeglRectangle *rect,
689 gboolean clear_cache)
690 {
691 GHashTable *regions;
692 GeglVisitor *visitor;
693
694 g_return_if_fail (GEGL_IS_NODE (node));
695
696 if (!rect)
697 rect = &node->have_rect;
698
699 if (node->cache && clear_cache)
700 gegl_buffer_clear (GEGL_BUFFER (node->cache), rect);
701
702 regions = g_hash_table_new_full (NULL, NULL, NULL,
703 (GDestroyNotify) gegl_region_destroy);
704
705 g_hash_table_insert (regions, node, gegl_region_rectangle (rect));
706
707 visitor = gegl_callback_visitor_new (gegl_node_invalidated_invalidate_node,
708 regions);
709
710 gegl_visitor_traverse_reverse_topological (visitor,
711 gegl_node_get_output_visitable (node));
712
713 g_object_unref (visitor);
714 g_hash_table_unref (regions);
715 }
716
717 #else /* ! GEGL_NODE_INVALIDATED_USE_REGIONS */
718
719 static gboolean
gegl_node_invalidated_invalidate_node(GeglNode * node,gpointer data)720 gegl_node_invalidated_invalidate_node (GeglNode *node,
721 gpointer data)
722 {
723 GHashTable *rects = data;
724 const GeglRectangle *rect = g_hash_table_lookup (rects, node);
725 GSList *iter;
726
727 node->valid_have_rect = FALSE;
728
729 if (node->cache)
730 gegl_cache_invalidate (node->cache, rect);
731
732 g_signal_emit (node, gegl_node_signals[INVALIDATED], 0,
733 rect, NULL);
734
735 for (iter = node->priv->sink_connections; iter; iter = g_slist_next (iter))
736 {
737 GeglConnection *connection = iter->data;
738 GeglNode *sink_node = gegl_connection_get_sink_node (connection);
739 GeglPad *sink_pad = gegl_connection_get_sink_pad (connection);
740 GeglRectangle *sink_rect = g_hash_table_lookup (rects, sink_node);
741
742 if (! sink_rect)
743 {
744 sink_rect = gegl_rectangle_new (0, 0, 0, 0);
745
746 g_hash_table_insert (rects, sink_node, sink_rect);
747 }
748
749 if (sink_node->operation)
750 {
751 GeglRectangle invalidated_rect;
752
753 invalidated_rect = gegl_operation_get_invalidated_by_change (
754 sink_node->operation,
755 gegl_pad_get_name (sink_pad), rect);
756
757 gegl_rectangle_bounding_box (sink_rect, sink_rect, &invalidated_rect);
758 }
759 else
760 {
761 gegl_rectangle_bounding_box (sink_rect, sink_rect, rect);
762 }
763 }
764
765 return FALSE;
766 }
767
768 void
gegl_node_invalidated(GeglNode * node,const GeglRectangle * rect,gboolean clear_cache)769 gegl_node_invalidated (GeglNode *node,
770 const GeglRectangle *rect,
771 gboolean clear_cache)
772 {
773 GHashTable *rects;
774 GeglVisitor *visitor;
775
776 g_return_if_fail (GEGL_IS_NODE (node));
777
778 if (!rect)
779 rect = &node->have_rect;
780
781 if (node->cache && clear_cache)
782 gegl_buffer_clear (GEGL_BUFFER (node->cache), rect);
783
784 rects = g_hash_table_new_full (NULL, NULL, NULL, g_free);
785
786 g_hash_table_insert (rects, node, g_memdup (rect, sizeof (GeglRectangle)));
787
788 visitor = gegl_callback_visitor_new (gegl_node_invalidated_invalidate_node,
789 rects);
790
791 gegl_visitor_traverse_reverse_topological (visitor,
792 gegl_node_get_output_visitable (node));
793
794 g_object_unref (visitor);
795 g_hash_table_unref (rects);
796 }
797
798 #endif /* ! GEGL_NODE_INVALIDATED_USE_REGIONS */
799
800 static void
gegl_node_source_invalidated(GeglNode * source,GeglPad * destination_pad,const GeglRectangle * rect)801 gegl_node_source_invalidated (GeglNode *source,
802 GeglPad *destination_pad,
803 const GeglRectangle *rect)
804 {
805 GeglNode *destination = gegl_pad_get_node (destination_pad);
806 GeglRectangle dirty_rect;
807
808 GEGL_NOTE (GEGL_DEBUG_INVALIDATION, "%s.%s is dirtied from %s (%i,%i %i×%i)",
809 gegl_node_get_debug_name (destination), gegl_pad_get_name (destination_pad),
810 gegl_node_get_debug_name (source),
811 rect->x, rect->y,
812 rect->width, rect->height);
813
814 if (destination->operation)
815 {
816 dirty_rect =
817 gegl_operation_get_invalidated_by_change (destination->operation,
818 gegl_pad_get_name (destination_pad),
819 rect);
820 }
821 else
822 {
823 dirty_rect = *rect;
824 }
825
826 gegl_node_invalidated (destination, &dirty_rect, FALSE);
827 }
828
829 static gboolean
gegl_node_has_source_node_equals(GeglNode * node,gpointer potential_source)830 gegl_node_has_source_node_equals (GeglNode *node,
831 gpointer potential_source)
832 {
833 return node == potential_source;
834 }
835
836 static gboolean
gegl_node_has_source(GeglNode * self,GeglNode * potential_source)837 gegl_node_has_source (GeglNode *self,
838 GeglNode *potential_source)
839 {
840 GeglVisitor *visitor;
841 gboolean found;
842
843 visitor = gegl_callback_visitor_new (gegl_node_has_source_node_equals,
844 potential_source);
845
846 found = gegl_visitor_traverse (visitor, GEGL_VISITABLE (self));
847
848 g_object_unref (visitor);
849
850 return found;
851 }
852
853 gboolean
gegl_node_is_graph(GeglNode * node)854 gegl_node_is_graph (GeglNode *node)
855 {
856 g_return_val_if_fail (node, FALSE);
857 g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
858 return node->is_graph;
859 }
860
861 gboolean
gegl_node_connect_from(GeglNode * sink,const gchar * sink_pad_name,GeglNode * source,const gchar * source_pad_name)862 gegl_node_connect_from (GeglNode *sink,
863 const gchar *sink_pad_name,
864 GeglNode *source,
865 const gchar *source_pad_name)
866 {
867 GeglNode *real_sink = sink;
868 GeglNode *real_source = source;
869 const gchar *real_sink_pad_name = sink_pad_name;
870 const gchar *real_source_pad_name = source_pad_name;
871
872 g_return_val_if_fail (GEGL_IS_NODE (sink), FALSE);
873 g_return_val_if_fail (sink_pad_name != NULL, FALSE);
874 g_return_val_if_fail (GEGL_IS_NODE (source), FALSE);
875 g_return_val_if_fail (source_pad_name != NULL, FALSE);
876
877 if (gegl_node_has_source (source, sink))
878 {
879 g_warning ("Construction of loop requested, bailing\n");
880 return FALSE;
881 }
882
883 /* For graph nodes we implicitly use the proxy nodes */
884 if (sink->is_graph)
885 {
886 real_sink = gegl_node_get_input_proxy (sink, sink_pad_name);
887
888 /* The name of the input pad of proxynop input nodes is always
889 * "input"
890 */
891 real_sink_pad_name = "input";
892 }
893 if (source->is_graph)
894 {
895 real_source = gegl_node_get_output_proxy (source, source_pad_name);
896
897 /* The name of the output pad of proxynop output nodes is always
898 * "output"
899 */
900 real_source_pad_name = "output";
901 }
902
903 if (gegl_node_pads_exist (real_sink, real_sink_pad_name, real_source, real_source_pad_name))
904 {
905 GeglPad *other_pad;
906 GeglPad *sink_pad = gegl_node_get_pad (real_sink, real_sink_pad_name);
907 GeglPad *source_pad = gegl_node_get_pad (real_source, real_source_pad_name);
908 GeglConnection *connection;
909
910 other_pad = gegl_pad_get_connected_to (sink_pad);
911 if (source_pad == other_pad)
912 return TRUE;
913
914 gegl_node_disconnect (real_sink, real_sink_pad_name);
915
916 connection = gegl_pad_connect (sink_pad, source_pad);
917 gegl_connection_set_sink_node (connection, real_sink);
918 gegl_connection_set_source_node (connection, real_source);
919
920 real_sink->priv->source_connections = g_slist_prepend (real_sink->priv->source_connections, connection);
921 real_source->priv->sink_connections = g_slist_prepend (real_source->priv->sink_connections, connection);
922
923 gegl_node_source_invalidated (real_source, sink_pad, &real_source->have_rect);
924
925 return TRUE;
926 }
927
928 return FALSE;
929 }
930
931 gboolean
gegl_node_disconnect(GeglNode * sink,const gchar * sink_pad_name)932 gegl_node_disconnect (GeglNode *sink,
933 const gchar *sink_pad_name)
934 {
935 GeglNode *real_sink = sink;
936 const gchar *real_sink_pad_name = sink_pad_name;
937
938 g_return_val_if_fail (GEGL_IS_NODE (sink), FALSE);
939 g_return_val_if_fail (sink_pad_name != NULL, FALSE);
940
941 /* For graph nodes we implicitly use the proxy nodes */
942 if (sink->is_graph)
943 {
944 real_sink = gegl_node_get_input_proxy (sink, sink_pad_name);
945
946 /* The name of the input pad of proxynop input nodes is always
947 * "input"
948 */
949 real_sink_pad_name = "input";
950 }
951
952 if (gegl_node_pads_exist (real_sink, real_sink_pad_name, NULL, NULL))
953 {
954 GeglPad *sink_pad = gegl_node_get_pad (real_sink, real_sink_pad_name);
955 GeglConnection *connection = gegl_node_find_connection (real_sink, sink_pad);
956 GeglNode *source;
957 GeglPad *source_pad;
958
959 if (!connection)
960 return FALSE;
961
962 source_pad = gegl_connection_get_source_pad (connection);
963 source = gegl_connection_get_source_node (connection);
964
965 gegl_node_source_invalidated (source, sink_pad, &source->have_rect);
966
967 gegl_pad_disconnect (sink_pad, source_pad, connection);
968
969 real_sink->priv->source_connections = g_slist_remove (real_sink->priv->source_connections, connection);
970 source->priv->sink_connections = g_slist_remove (source->priv->sink_connections, connection);
971
972 gegl_connection_destroy (connection);
973
974
975 return TRUE;
976 }
977
978 return FALSE;
979 }
980
981 static void
gegl_node_disconnect_sources(GeglNode * self)982 gegl_node_disconnect_sources (GeglNode *self)
983 {
984 while (TRUE)
985 {
986 GeglConnection *connection = g_slist_nth_data (self->priv->source_connections, 0);
987
988 if (connection)
989 {
990 GeglNode *sink = gegl_connection_get_sink_node (connection);
991 GeglPad *sink_pad = gegl_connection_get_sink_pad (connection);
992 const gchar *sink_pad_name = gegl_pad_get_name (sink_pad);
993
994 g_assert (self == sink);
995
996 gegl_node_disconnect (sink, sink_pad_name);
997 }
998 else
999 break;
1000 }
1001 }
1002
1003 static void
gegl_node_disconnect_sinks(GeglNode * self)1004 gegl_node_disconnect_sinks (GeglNode *self)
1005 {
1006 while (TRUE)
1007 {
1008 GeglConnection *connection = g_slist_nth_data (self->priv->sink_connections, 0);
1009
1010 if (connection)
1011 {
1012 GeglNode *sink = gegl_connection_get_sink_node (connection);
1013 GeglNode *source = gegl_connection_get_source_node (connection);
1014 GeglPad *sink_pad = gegl_connection_get_sink_pad (connection);
1015 const gchar *sink_pad_name = gegl_pad_get_name (sink_pad);
1016
1017 g_assert (self == source);
1018
1019 gegl_node_disconnect (sink, sink_pad_name);
1020 }
1021 else
1022 break;
1023 }
1024 }
1025
1026 /**
1027 * gegl_node_num_sinks:
1028 * @self: a #GeglNode.
1029 *
1030 * Gets the number of sinks
1031 *
1032 * Returns: number of sinks
1033 **/
1034 gint
gegl_node_get_num_sinks(GeglNode * self)1035 gegl_node_get_num_sinks (GeglNode *self)
1036 {
1037 g_return_val_if_fail (GEGL_IS_NODE (self), -1);
1038
1039 return g_slist_length (self->priv->sink_connections);
1040 }
1041
1042 /**
1043 * gegl_node_get_sinks:
1044 * @self: a #GeglNode.
1045 *
1046 * Gets list of sink connections attached to this self.
1047 *
1048 * Returns: list of sink connections.
1049 **/
1050 GSList *
gegl_node_get_sinks(GeglNode * self)1051 gegl_node_get_sinks (GeglNode *self)
1052 {
1053 g_return_val_if_fail (GEGL_IS_NODE (self), FALSE);
1054
1055 return self->priv->sink_connections;
1056 }
1057
1058 void
gegl_node_link(GeglNode * source,GeglNode * sink)1059 gegl_node_link (GeglNode *source,
1060 GeglNode *sink)
1061 {
1062 g_return_if_fail (GEGL_IS_NODE (source));
1063 g_return_if_fail (GEGL_IS_NODE (sink));
1064
1065 /* using connect_to is more natural here, but leads to an extra
1066 * function call, perhaps connect_to and connect_from should be swapped?
1067 */
1068 gegl_node_connect_to (source, "output", sink, "input");
1069 }
1070
1071 void
gegl_node_link_many(GeglNode * source,GeglNode * dest,...)1072 gegl_node_link_many (GeglNode *source,
1073 GeglNode *dest,
1074 ...)
1075 {
1076 va_list var_args;
1077
1078 g_return_if_fail (GEGL_IS_NODE (source));
1079 g_return_if_fail (GEGL_IS_NODE (dest));
1080
1081 va_start (var_args, dest);
1082 while (dest)
1083 {
1084 gegl_node_link (source, dest);
1085 source = dest;
1086 dest = va_arg (var_args, GeglNode *);
1087 }
1088 va_end (var_args);
1089 }
1090
1091 static GeglEvalManager *
gegl_node_get_eval_manager(GeglNode * self)1092 gegl_node_get_eval_manager (GeglNode *self)
1093 {
1094 if (!self->priv->eval_manager)
1095 self->priv->eval_manager = gegl_eval_manager_new (self, "output");
1096 return self->priv->eval_manager;
1097 }
1098
1099 static GeglBuffer *
gegl_node_apply_roi(GeglNode * self,const GeglRectangle * roi,gint level)1100 gegl_node_apply_roi (GeglNode *self,
1101 const GeglRectangle *roi,
1102 gint level)
1103 {
1104 GeglEvalManager *eval_manager = gegl_node_get_eval_manager (self);
1105
1106 if (roi)
1107 {
1108 return gegl_eval_manager_apply (eval_manager, roi, level);
1109 }
1110 else
1111 {
1112 GeglRectangle node_bbox = gegl_node_get_bounding_box (self);
1113 return gegl_eval_manager_apply (eval_manager, &node_bbox, level);
1114 }
1115 }
1116
1117 void
gegl_node_blit_buffer(GeglNode * self,GeglBuffer * buffer,const GeglRectangle * roi,gint level,GeglAbyssPolicy abyss_policy)1118 gegl_node_blit_buffer (GeglNode *self,
1119 GeglBuffer *buffer,
1120 const GeglRectangle *roi,
1121 gint level,
1122 GeglAbyssPolicy abyss_policy)
1123 {
1124 // XXX: make use of abyss_policy
1125
1126 GeglEvalManager *eval_manager;
1127 GeglBuffer *result;
1128 GeglRectangle request;
1129
1130 eval_manager = gegl_node_get_eval_manager (self);
1131
1132 if (roi)
1133 request = *roi;
1134 else if (buffer)
1135 request = *gegl_buffer_get_extent (buffer);
1136 else
1137 request = gegl_node_get_bounding_box (self);
1138
1139 result = gegl_eval_manager_apply (eval_manager, &request, level);
1140
1141 if (result)
1142 {
1143 if (buffer && buffer != result)
1144 gegl_buffer_copy (result, &request, GEGL_ABYSS_NONE, buffer, NULL);
1145 g_object_unref (result);
1146 }
1147 }
1148
gegl_mipmap_rendering_enabled(void)1149 static inline gboolean gegl_mipmap_rendering_enabled (void)
1150 {
1151 return gegl_config()->mipmap_rendering;
1152 }
1153
1154 void
gegl_node_blit(GeglNode * self,gdouble scale,const GeglRectangle * roi,const Babl * format,gpointer destination_buf,gint rowstride,GeglBlitFlags flags)1155 gegl_node_blit (GeglNode *self,
1156 gdouble scale,
1157 const GeglRectangle *roi,
1158 const Babl *format,
1159 gpointer destination_buf,
1160 gint rowstride,
1161 GeglBlitFlags flags)
1162 {
1163 gint interpolation = flags & (GEGL_BUFFER_FILTER_ALL);
1164 flags &= 0xf;
1165
1166 g_return_if_fail (GEGL_IS_NODE (self));
1167 g_return_if_fail (roi != NULL);
1168
1169 if (rowstride == GEGL_AUTO_ROWSTRIDE && format)
1170 rowstride = babl_format_get_bytes_per_pixel (format) * roi->width;
1171
1172 if (flags == 0) // DEFAULT, just render, caching only if graph is explicitly caching itself
1173 {
1174 GeglBuffer *buffer;
1175
1176 if (scale != 1.0)
1177 {
1178 const GeglRectangle unscaled_roi = _gegl_get_required_for_scale (roi, scale);
1179
1180 buffer = gegl_node_apply_roi (self, &unscaled_roi,
1181 gegl_mipmap_rendering_enabled()?gegl_level_from_scale (scale):0);
1182 }
1183 else
1184 {
1185 buffer = gegl_node_apply_roi (self, roi, 0);
1186 }
1187 if (buffer && destination_buf)
1188 gegl_buffer_get (buffer, roi, scale, format, destination_buf, rowstride, GEGL_ABYSS_NONE | interpolation);
1189
1190 g_clear_object (&buffer);
1191 }
1192 else if (flags & GEGL_BLIT_CACHE)
1193 {
1194 GeglCache *cache;
1195 GeglBuffer *buffer;
1196
1197 /* make sure we have an output format for the cache */
1198 gegl_eval_manager_prepare (gegl_node_get_eval_manager (self));
1199
1200 cache = gegl_node_get_cache (self);
1201 buffer = GEGL_BUFFER (cache);
1202
1203 if (!(flags & GEGL_BLIT_DIRTY))
1204 {
1205 if (scale != 1.0)
1206 {
1207 const GeglRectangle unscaled_roi = _gegl_get_required_for_scale (roi, scale);
1208 gint level = gegl_mipmap_rendering_enabled()?gegl_level_from_scale (scale):0;
1209
1210 gegl_node_blit_buffer (self, buffer, &unscaled_roi, level, GEGL_ABYSS_NONE);
1211 gegl_cache_computed (cache, &unscaled_roi, level);
1212 }
1213 else
1214 {
1215 gegl_node_blit_buffer (self, buffer, roi, 0, GEGL_ABYSS_NONE);
1216 gegl_cache_computed (cache, roi, 0);
1217 }
1218 }
1219
1220 if (destination_buf && cache)
1221 {
1222 gegl_buffer_get (buffer, roi, scale,
1223 format, destination_buf, rowstride,
1224 GEGL_ABYSS_NONE|interpolation);
1225 }
1226 }
1227 }
1228
1229 static GSList *
gegl_node_get_depends_on(GeglNode * self)1230 gegl_node_get_depends_on (GeglNode *self)
1231 {
1232 GSList *depends_on = NULL;
1233 GSList *llink;
1234
1235 for (llink = self->priv->source_connections; llink; llink = g_slist_next (llink))
1236 {
1237 GeglConnection *connection = llink->data;
1238 GeglNode *source_node;
1239
1240 source_node = gegl_connection_get_source_node (connection);
1241
1242 depends_on = g_slist_prepend (depends_on, source_node);
1243 }
1244
1245 return depends_on;
1246 }
1247
1248 void
gegl_node_dump_depends_on(GeglNode * self)1249 gegl_node_dump_depends_on (GeglNode *self)
1250 {
1251 GSList *depends_on = gegl_node_get_depends_on (self);
1252 GSList *iter = NULL;
1253
1254 g_print ("GeglNode %p depends on:\n", self);
1255
1256 for (iter = depends_on; iter; iter = iter->next)
1257 {
1258 GeglNode *source_node = depends_on->data;
1259 g_print (" %s\n", gegl_node_get_debug_name (source_node));
1260 }
1261
1262 g_slist_free (depends_on);
1263 }
1264
1265 static gboolean
gegl_node_visitable_accept(GeglVisitable * visitable,GeglVisitor * visitor)1266 gegl_node_visitable_accept (GeglVisitable *visitable,
1267 GeglVisitor *visitor)
1268 {
1269 return gegl_visitor_visit_node (visitor, (GeglNode *) visitable);
1270 }
1271
1272 static GSList *
gegl_node_visitable_depends_on(GeglVisitable * visitable)1273 gegl_node_visitable_depends_on (GeglVisitable *visitable)
1274 {
1275 GeglNode *self = GEGL_NODE (visitable);
1276
1277 return gegl_node_get_depends_on (self);
1278 }
1279
1280 static void
gegl_node_set_op_class(GeglNode * node,const gchar * op_class,const gchar * first_property,va_list var_args)1281 gegl_node_set_op_class (GeglNode *node,
1282 const gchar *op_class,
1283 const gchar *first_property,
1284 va_list var_args)
1285 {
1286 g_return_if_fail (GEGL_IS_NODE (node));
1287 g_return_if_fail (op_class);
1288
1289 if (op_class && op_class[0] != '\0')
1290 {
1291 GType type;
1292 GeglOperation *operation;
1293
1294 type = gegl_operation_gtype_from_name (op_class);
1295
1296 if (!type)
1297 {
1298 g_warning ("Failed to set operation type %s, using a passthrough op instead", op_class);
1299 if (strcmp (op_class, "gegl:nop"))
1300 {
1301 gegl_node_set_op_class (node, "gegl:nop", NULL, var_args);
1302 }
1303 else
1304 {
1305 g_warning ("The failing op was 'gegl:nop' this means that GEGL was unable to locate any of it's\n"
1306 "plug-ins. Try making GEGL_PATH point to the directory containing the .so|.dll\n"
1307 "files with the image processing plug-ins, optionally you could try to make it\n"
1308 "point to the operations directory of a GEGL sourcetree with a build.");
1309 }
1310 return;
1311 }
1312
1313 if (node->operation &&
1314 type == G_OBJECT_TYPE (node->operation) &&
1315 first_property)
1316 {
1317 gegl_node_set_valist (node, first_property, var_args);
1318 return;
1319 }
1320
1321 operation = GEGL_OPERATION (g_object_new_valist (type, first_property,
1322 var_args));
1323 gegl_node_set_operation_object (node, operation);
1324 g_object_unref (operation);
1325 }
1326 }
1327
1328 static gboolean
gegl_node_invalidate_have_rect(GObject * gobject,gpointer foo,gpointer user_data)1329 gegl_node_invalidate_have_rect (GObject *gobject,
1330 gpointer foo,
1331 gpointer user_data)
1332 {
1333 GEGL_NODE (user_data)->valid_have_rect = FALSE;
1334 return TRUE;
1335 }
1336
1337
1338 static void
gegl_node_property_changed(GObject * gobject,GParamSpec * arg1,gpointer user_data)1339 gegl_node_property_changed (GObject *gobject,
1340 GParamSpec *arg1,
1341 gpointer user_data)
1342 {
1343 GeglNode *self = GEGL_NODE (user_data);
1344
1345 if (arg1 != user_data &&
1346 ((arg1 &&
1347 arg1->value_type != GEGL_TYPE_BUFFER) ||
1348 (self->operation && !arg1)))
1349 {
1350 if (self->operation && !arg1)
1351 { /* these means we were called due to a operation change
1352
1353 FIXME: The logic of this if is not quite intuitive,
1354 perhaps the thing being checked should be slightly different,
1355 or perhaps a bug lurks here?
1356 */
1357 GeglRectangle dirty_rect;
1358 /* GeglRectangle new_have_rect;*/
1359
1360 dirty_rect = self->have_rect;
1361 /*new_have_rect = gegl_node_get_bounding_box (self);
1362
1363 gegl_rectangle_bounding_box (&dirty_rect,
1364 &dirty_rect,
1365 &new_have_rect);*/
1366
1367 gegl_node_invalidated (self, &dirty_rect, FALSE);
1368 }
1369 else
1370 {
1371 /* we were called due to a property change */
1372 GeglRectangle dirty_rect;
1373 GeglRectangle new_have_rect;
1374
1375 dirty_rect = self->have_rect;
1376 new_have_rect = gegl_node_get_bounding_box (self);
1377
1378 gegl_rectangle_bounding_box (&dirty_rect,
1379 &dirty_rect,
1380 &new_have_rect);
1381
1382 gegl_node_invalidated (self, &dirty_rect, FALSE);
1383 }
1384 }
1385
1386 if (arg1)
1387 g_object_notify_by_pspec (G_OBJECT (self), arg1);
1388 }
1389
1390 static void
gegl_node_set_operation_object(GeglNode * self,GeglOperation * operation)1391 gegl_node_set_operation_object (GeglNode *self,
1392 GeglOperation *operation)
1393 {
1394 GeglNode **consumer_nodes = NULL;
1395 const gchar **consumer_names = NULL;
1396 GeglNode *input = NULL;
1397 GeglNode *aux = NULL;
1398 GeglNode *aux2 = NULL;
1399
1400 g_return_if_fail (GEGL_IS_NODE (self));
1401
1402 if (!operation)
1403 return;
1404
1405 g_return_if_fail (GEGL_IS_OPERATION (operation));
1406
1407 if (gegl_node_has_pad (self, "output"))
1408 gegl_node_get_consumers (self, "output", &consumer_nodes, &consumer_names);
1409
1410 input = gegl_node_get_producer (self, "input", NULL);
1411 aux = gegl_node_get_producer (self, "aux", NULL);
1412 aux2 = gegl_node_get_producer (self, "aux2", NULL);
1413
1414 gegl_node_disconnect_sources (self);
1415 gegl_node_disconnect_sinks (self);
1416
1417 g_set_object (&self->operation, operation);
1418
1419 /* Delete all the pads from the previous operation */
1420 while (self->pads)
1421 gegl_node_remove_pad (self, self->pads->data);
1422
1423 gegl_node_remove_children (self);
1424
1425 gegl_operation_attach (operation, self);
1426
1427 /* FIXME: This should handle all input pads instead of just these 3 */
1428 if (input)
1429 gegl_node_connect_from (self, "input", input, "output");
1430 if (aux)
1431 gegl_node_connect_from (self, "aux", aux, "output");
1432 if (aux2)
1433 gegl_node_connect_from (self, "aux2", aux2, "output");
1434
1435 if (consumer_nodes)
1436 {
1437 for (gint i = 0; consumer_nodes[i]; ++i)
1438 {
1439 GeglNode *output = consumer_nodes[i];
1440 const gchar *output_dest_pad = consumer_names[i];
1441
1442 if (output)
1443 gegl_node_connect_to (self, "output", output, output_dest_pad);
1444 }
1445
1446 g_free (consumer_nodes);
1447 g_free (consumer_names);
1448 }
1449
1450 g_signal_connect (G_OBJECT (operation), "notify", G_CALLBACK (gegl_node_invalidate_have_rect), self);
1451 g_signal_connect (G_OBJECT (operation), "notify", G_CALLBACK (gegl_node_property_changed), self);
1452
1453 gegl_node_update_debug_name (self);
1454
1455 gegl_node_property_changed (G_OBJECT (operation), (GParamSpec *) NULL, self);
1456 }
1457
1458 void
gegl_node_set(GeglNode * self,const gchar * first_property_name,...)1459 gegl_node_set (GeglNode *self,
1460 const gchar *first_property_name,
1461 ...)
1462 {
1463 va_list var_args;
1464
1465 g_return_if_fail (GEGL_IS_NODE (self));
1466
1467 va_start (var_args, first_property_name);
1468 gegl_node_set_valist (self, first_property_name, var_args);
1469 va_end (var_args);
1470 }
1471
1472 void
gegl_node_get(GeglNode * self,const gchar * first_property_name,...)1473 gegl_node_get (GeglNode *self,
1474 const gchar *first_property_name,
1475 ...)
1476 {
1477 va_list var_args;
1478
1479 g_return_if_fail (GEGL_IS_NODE (self));
1480 g_return_if_fail (self->is_graph || GEGL_IS_OPERATION (self->operation));
1481
1482 va_start (var_args, first_property_name);
1483 gegl_node_get_valist (self, first_property_name, var_args);
1484 va_end (var_args);
1485 }
1486
1487 void
gegl_node_set_valist(GeglNode * self,const gchar * first_property_name,va_list var_args)1488 gegl_node_set_valist (GeglNode *self,
1489 const gchar *first_property_name,
1490 va_list var_args)
1491 {
1492 const gchar *property_name;
1493
1494 g_return_if_fail (GEGL_IS_NODE (self));
1495
1496 g_object_freeze_notify (G_OBJECT (self));
1497
1498 if (self->operation)
1499 g_object_freeze_notify (G_OBJECT (self->operation));
1500
1501 property_name = first_property_name;
1502 while (property_name)
1503 {
1504 if (!strcmp (property_name, "operation"))
1505 {
1506 const gchar *op_class;
1507 const gchar *op_first_property;
1508
1509 op_class = va_arg (var_args, gchar *);
1510 op_first_property = va_arg (var_args, gchar *);
1511
1512 if (self->operation)
1513 g_object_thaw_notify (G_OBJECT (self->operation));
1514
1515 /* pass the following properties as construction properties
1516 * to the operation */
1517 gegl_node_set_op_class (self, op_class, op_first_property, var_args);
1518
1519 if (self->operation)
1520 g_object_freeze_notify (G_OBJECT (self->operation));
1521
1522 break;
1523 }
1524 else
1525 {
1526 GValue value = { 0, };
1527 GParamSpec *pspec = NULL;
1528 gchar *error = NULL;
1529 GObject *object = NULL;
1530
1531 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self),
1532 property_name);
1533 if (pspec)
1534 {
1535 object = G_OBJECT (self);
1536 }
1537 else if (self->operation)
1538 {
1539 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self->operation),
1540 property_name);
1541 if (pspec)
1542 object = G_OBJECT (self->operation);
1543 }
1544
1545 if (!object)
1546 {
1547 g_warning ("%s is not a valid property of %s",
1548 property_name,
1549 gegl_node_get_debug_name (self));
1550 break;
1551 }
1552 else
1553 {
1554 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1555 G_VALUE_COLLECT (&value, var_args, 0, &error);
1556 if (error)
1557 {
1558 g_warning ("%s: %s", G_STRFUNC, error);
1559 g_free (error);
1560 g_value_unset (&value);
1561 break;
1562 }
1563 g_object_set_property (object, property_name, &value);
1564 g_value_unset (&value);
1565 }
1566 }
1567
1568 property_name = va_arg (var_args, gchar *);
1569 }
1570
1571 if (self->operation)
1572 g_object_thaw_notify (G_OBJECT (self->operation));
1573
1574 g_object_thaw_notify (G_OBJECT (self));
1575 }
1576
1577 void
gegl_node_get_valist(GeglNode * self,const gchar * first_property_name,va_list var_args)1578 gegl_node_get_valist (GeglNode *self,
1579 const gchar *first_property_name,
1580 va_list var_args)
1581 {
1582 const gchar *property_name;
1583
1584 g_return_if_fail (G_IS_OBJECT (self));
1585
1586 property_name = first_property_name;
1587
1588 while (property_name)
1589 {
1590 GValue value = { 0, };
1591 gchar *error;
1592
1593 gegl_node_get_property (self, property_name, &value);
1594 if (!G_IS_VALUE (&value))
1595 break;
1596
1597 G_VALUE_LCOPY (&value, var_args, 0, &error);
1598 if (error)
1599 {
1600 g_warning ("%s: %s", G_STRFUNC, error);
1601 g_free (error);
1602 g_value_unset (&value);
1603 break;
1604 }
1605 g_value_unset (&value);
1606
1607 property_name = va_arg (var_args, gchar *);
1608 }
1609 }
1610
1611 void
gegl_node_set_property(GeglNode * self,const gchar * property_name,const GValue * value)1612 gegl_node_set_property (GeglNode *self,
1613 const gchar *property_name,
1614 const GValue *value)
1615 {
1616 GParamSpec *pspec;
1617
1618 g_return_if_fail (GEGL_IS_NODE (self));
1619 g_return_if_fail (property_name != NULL);
1620 g_return_if_fail (value != NULL);
1621
1622 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self), property_name);
1623 if (pspec)
1624 {
1625 g_object_set_property (G_OBJECT (self), property_name, value);
1626 return;
1627 }
1628
1629 if (self->operation)
1630 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self->operation), property_name);
1631 if (pspec)
1632 {
1633 if (G_IS_PARAM_SPEC_ENUM (pspec) && G_VALUE_HOLDS (value, G_TYPE_STRING))
1634 {
1635 GEnumClass *enum_class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
1636 const gchar *value_string = g_value_get_string (value);
1637 GEnumValue *enum_value = NULL;
1638
1639 enum_value = g_enum_get_value_by_name (enum_class, value_string);
1640 if (!enum_value)
1641 enum_value = g_enum_get_value_by_nick (enum_class, value_string);
1642
1643 if (enum_value)
1644 {
1645 GValue value = G_VALUE_INIT;
1646 g_value_init (&value, G_TYPE_FROM_CLASS (&enum_class->g_type_class));
1647 g_value_set_enum (&value, enum_value->value);
1648 g_object_set_property (G_OBJECT (self->operation), property_name, &value);
1649 g_value_unset (&value);
1650 return;
1651 }
1652
1653 g_warning ("Could not convert %s to a valid enum value for %s",
1654 value_string,
1655 property_name);
1656 }
1657 g_object_set_property (G_OBJECT (self->operation), property_name, value);
1658 return;
1659 }
1660
1661 g_warning ("%s is not a valid property of %s",
1662 property_name,
1663 gegl_node_get_debug_name (self));
1664 }
1665
1666 void
gegl_node_get_property(GeglNode * self,const gchar * property_name,GValue * value)1667 gegl_node_get_property (GeglNode *self,
1668 const gchar *property_name,
1669 GValue *value)
1670 {
1671 GParamSpec *pspec;
1672
1673 g_return_if_fail (GEGL_IS_NODE (self));
1674 g_return_if_fail (property_name != NULL);
1675 g_return_if_fail (value != NULL);
1676
1677 /* Unlinke GObject's get_property this function also
1678 * accepts a zero'd GValue and will fill it with the
1679 * correct type automaticaly.
1680 */
1681
1682 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self), property_name);
1683 if (pspec)
1684 {
1685 if (!G_IS_VALUE (value))
1686 g_value_init (value, pspec->value_type);
1687 g_object_get_property (G_OBJECT (self), property_name, value);
1688 return;
1689 }
1690
1691 if (self->operation)
1692 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self->operation), property_name);
1693 if (pspec)
1694 {
1695 if (!G_IS_VALUE (value))
1696 g_value_init (value, pspec->value_type);
1697 g_object_get_property (G_OBJECT (self->operation), property_name, value);
1698 return;
1699 }
1700
1701 g_warning ("%s is not a valid property of %s",
1702 property_name,
1703 gegl_node_get_debug_name (self));
1704 }
1705
1706 GParamSpec *
gegl_node_find_property(GeglNode * self,const gchar * property_name)1707 gegl_node_find_property (GeglNode *self,
1708 const gchar *property_name)
1709 {
1710 GParamSpec *pspec = NULL;
1711
1712 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
1713 g_return_val_if_fail (property_name != NULL, NULL);
1714
1715 if (self->operation)
1716 pspec = g_object_class_find_property (
1717 G_OBJECT_GET_CLASS (G_OBJECT (self->operation)), property_name);
1718 if (!pspec)
1719 pspec = g_object_class_find_property (
1720 G_OBJECT_GET_CLASS (G_OBJECT (self)), property_name);
1721 return pspec;
1722 }
1723
1724 const gchar *
gegl_node_get_operation(const GeglNode * node)1725 gegl_node_get_operation (const GeglNode *node)
1726 {
1727 if (node == NULL)
1728 return NULL;
1729
1730 if (node->operation == NULL)
1731 {
1732 if (node->is_graph)
1733 return "GraphNode";
1734
1735 return NULL;
1736 }
1737
1738 return GEGL_OPERATION_GET_CLASS (node->operation)->name;
1739 }
1740
1741 GeglOperation *
gegl_node_get_gegl_operation(GeglNode * node)1742 gegl_node_get_gegl_operation (GeglNode *node)
1743 {
1744 if (node == NULL)
1745 return NULL;
1746
1747 return node->operation;
1748 }
1749
1750 static void
gegl_node_update_debug_name(GeglNode * node)1751 gegl_node_update_debug_name (GeglNode *node)
1752 {
1753 const gchar *name = gegl_node_get_name (node);
1754 const gchar *operation = gegl_node_get_operation (node);
1755 gchar *new_name = NULL;
1756
1757 g_return_if_fail (GEGL_IS_NODE (node));
1758
1759 g_free (node->priv->debug_name);
1760
1761 if (name && *name)
1762 new_name = g_strdup_printf ("%s '%s' %p", operation ? operation : "(none)", name, node);
1763 else
1764 new_name = g_strdup_printf ("%s %p", operation ? operation : "(none)", node);
1765
1766 node->priv->debug_name = new_name;
1767 }
1768
1769 const gchar *
gegl_node_get_debug_name(GeglNode * node)1770 gegl_node_get_debug_name (GeglNode *node)
1771 {
1772 g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
1773
1774 return node->priv->debug_name;
1775 }
1776
1777 GeglNode *
gegl_node_get_producer(GeglNode * node,const gchar * pad_name,gchar ** output_pad_name)1778 gegl_node_get_producer (GeglNode *node,
1779 const gchar *pad_name,
1780 gchar **output_pad_name)
1781 {
1782 GeglNode *ret;
1783 gpointer pad;
1784
1785 if (!GEGL_IS_NODE (node))
1786 return NULL;
1787
1788 /* XXX: there should be public API to test if a node is
1789 * really a graph. So that the user of the API knows
1790 * the internals can be reached through the proxy nops
1791 */
1792 if (node->is_graph)
1793 {
1794 node = gegl_node_get_input_proxy (node, pad_name);
1795 if (!GEGL_IS_NODE (node))
1796 return NULL;
1797 pad_name = "input";
1798 }
1799
1800 pad = gegl_node_get_pad (node, pad_name);
1801
1802 if (!pad)
1803 return NULL;
1804 pad = gegl_pad_get_connected_to (pad);
1805 if (!pad)
1806 return NULL;
1807 ret = gegl_pad_get_node (pad);
1808
1809 if(ret)
1810 {
1811 const gchar *name;
1812 name = gegl_node_get_name (ret);
1813 if (name && !strcmp (name, "proxynop-output"))
1814 {
1815 ret = g_object_get_data (G_OBJECT (ret), "graph");
1816 /* XXX: needs testing whether this returns the correct value
1817 * for non "output" output pads.
1818 */
1819 if (output_pad_name)
1820 *output_pad_name = g_strdup (gegl_pad_get_name (pad));
1821 }
1822 else
1823 {
1824 if (output_pad_name)
1825 *output_pad_name = g_strdup (gegl_pad_get_name (pad));
1826 }
1827 }
1828 return ret;
1829 }
1830
1831 GeglRectangle
gegl_node_get_bounding_box(GeglNode * self)1832 gegl_node_get_bounding_box (GeglNode *self)
1833 {
1834 if (!self->valid_have_rect)
1835 {
1836 /* We need to construct an evaluation here because we need
1837 * to be sure we use the same logic as the eval manager to
1838 * calculate our bounds. We set our rect explicitly because
1839 * if we're a meta-op the eval manager may not actually
1840 * visit us in prepare.
1841 */
1842
1843 GeglEvalManager *eval = gegl_eval_manager_new (self, "output");
1844 self->have_rect = gegl_eval_manager_get_bounding_box (eval);
1845 self->valid_have_rect = TRUE;
1846 g_object_unref (eval);
1847 }
1848
1849 return self->have_rect;
1850 }
1851
1852 void
gegl_node_process(GeglNode * self)1853 gegl_node_process (GeglNode *self) /* XXX: add level argument? */
1854 {
1855 GeglProcessor *processor;
1856
1857 g_return_if_fail (GEGL_IS_NODE (self));
1858
1859 processor = gegl_node_new_processor (self, NULL);
1860
1861 while (gegl_processor_work (processor, NULL)) ;
1862 g_object_unref (processor);
1863 }
1864
1865 GeglNode *
gegl_node_detect(GeglNode * root,gint x,gint y)1866 gegl_node_detect (GeglNode *root,
1867 gint x,
1868 gint y)
1869 {
1870 if (root)
1871 {
1872 /* make sure the have rects are computed */
1873 /* FIXME: do not call this all the time! */
1874 gegl_node_get_bounding_box (root);
1875
1876 if (root->operation)
1877 return gegl_operation_detect (root->operation, x, y);
1878 else
1879 {
1880 if (root->is_graph)
1881 {
1882 GeglNode *foo = gegl_node_get_output_proxy (root, "output");
1883 if (foo && foo != root)
1884 return gegl_node_detect (foo, x, y);
1885 }
1886 }
1887 }
1888 return root;
1889 }
1890
1891 /* this is a bit hacky, but allows us to insert a node into the graph,
1892 * and avoid the full defined region of the entire graph to change
1893 */
1894 void
gegl_node_insert_before(GeglNode * self,GeglNode * to_be_inserted)1895 gegl_node_insert_before (GeglNode *self,
1896 GeglNode *to_be_inserted)
1897 {
1898 GeglNode *other;
1899 GeglRectangle rectangle;
1900
1901 g_return_if_fail (GEGL_IS_NODE (self));
1902 g_return_if_fail (GEGL_IS_NODE (to_be_inserted));
1903
1904 other = gegl_node_get_producer (self, "input", NULL); /*XXX: handle pad name */
1905 rectangle = gegl_node_get_bounding_box (to_be_inserted);
1906
1907 gegl_node_link_many (other, to_be_inserted, self, NULL);
1908
1909 /* emit the change ourselves */
1910 gegl_node_invalidated (self, &rectangle, FALSE);
1911 }
1912
1913 gint
gegl_node_get_consumers(GeglNode * node,const gchar * output_pad,GeglNode *** nodes,const gchar *** pads)1914 gegl_node_get_consumers (GeglNode *node,
1915 const gchar *output_pad,
1916 GeglNode ***nodes,
1917 const gchar ***pads)
1918 {
1919 GSList *connections;
1920 gint n_connections;
1921 GeglPad *pad;
1922 gchar **pasp = NULL;
1923
1924 g_return_val_if_fail (output_pad != NULL, 0);
1925
1926 if(node->is_graph)
1927 {
1928 node = gegl_node_get_output_proxy(node, output_pad);
1929 output_pad = "output";
1930 }
1931
1932 g_return_val_if_fail (GEGL_IS_NODE (node), 0);
1933
1934 pad = gegl_node_get_pad (node, output_pad);
1935
1936 if (!pad)
1937 {
1938 g_warning ("%s: no such pad %s for %s",
1939 G_STRFUNC, output_pad, gegl_node_get_debug_name (node));
1940 return 0;
1941 }
1942
1943 connections = gegl_pad_get_connections (pad);
1944 {
1945 GSList *iter;
1946 gint pasp_size = 0;
1947 gint i;
1948 gint pasp_pos = 0;
1949
1950 n_connections = g_slist_length (connections);
1951 pasp_size += (n_connections + 1) * sizeof (gchar *);
1952
1953 for (iter = connections; iter; iter = g_slist_next (iter))
1954 {
1955 GeglConnection *connection = iter->data;
1956 GeglPad *pad = gegl_connection_get_sink_pad (connection);
1957 pasp_size += strlen (gegl_pad_get_name (pad)) + 1;
1958 }
1959 if (nodes)
1960 *nodes = g_malloc ((n_connections + 1) * sizeof (void *));
1961 if (pads)
1962 {
1963 pasp = g_malloc (pasp_size);
1964 *pads = (void *) pasp;
1965 }
1966 i = 0;
1967 pasp_pos = (n_connections + 1) * sizeof (void *);
1968 for (iter = connections; iter; iter = g_slist_next (iter))
1969 {
1970 GeglConnection *connection = iter->data;
1971 GeglPad *pad = gegl_connection_get_sink_pad (connection);
1972 GeglNode *node = gegl_connection_get_sink_node (connection);
1973 const gchar *pad_name = gegl_pad_get_name (pad);
1974 const gchar *name = gegl_node_get_name(node);
1975
1976 gchar* proxy_name = g_strconcat("proxynop-", pad_name, NULL);
1977 if(!strcmp(name, proxy_name))
1978 {
1979 node = g_object_get_data(G_OBJECT(node), "graph");
1980 name = gegl_node_get_name(node);
1981 }
1982 else
1983 {
1984 }
1985 g_free (proxy_name);
1986
1987 if (nodes)
1988 (*nodes)[i] = node;
1989 if (pasp)
1990 {
1991 pasp[i] = ((gchar *) pasp) + pasp_pos;
1992 strcpy (pasp[i], pad_name);
1993 }
1994 pasp_pos += strlen (pad_name) + 1;
1995 i++;
1996 }
1997 if (nodes)
1998 (*nodes)[i] = NULL;
1999 if (pads)
2000 pasp[i] = NULL;
2001 }
2002 return n_connections;
2003 }
2004
2005
2006 void
gegl_node_emit_computed(GeglNode * node,const GeglRectangle * rect)2007 gegl_node_emit_computed (GeglNode *node,
2008 const GeglRectangle *rect)
2009 {
2010 g_signal_emit (node, gegl_node_signals[COMPUTED], 0, rect, NULL, NULL);
2011 }
2012
2013 gboolean
gegl_node_use_cache(GeglNode * node)2014 gegl_node_use_cache (GeglNode *node)
2015 {
2016 g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
2017
2018 switch (node->cache_policy)
2019 {
2020 case GEGL_CACHE_POLICY_AUTO:
2021 if (node->dont_cache)
2022 return FALSE;
2023 else if (node->operation)
2024 return gegl_operation_use_cache (node->operation);
2025 else
2026 return FALSE;
2027
2028 case GEGL_CACHE_POLICY_NEVER:
2029 return FALSE;
2030
2031 case GEGL_CACHE_POLICY_ALWAYS:
2032 return TRUE;
2033 }
2034
2035 g_return_val_if_reached (FALSE);
2036 }
2037
2038 GeglCache *
gegl_node_get_cache(GeglNode * node)2039 gegl_node_get_cache (GeglNode *node)
2040 {
2041 GeglPad *pad;
2042 GeglNode *real_node;
2043 const Babl *format = NULL;
2044 g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
2045
2046 pad = gegl_node_get_pad (node, "output");
2047 g_return_val_if_fail (pad, NULL);
2048
2049 real_node = gegl_pad_get_node (pad);
2050
2051 if (node != real_node)
2052 return gegl_node_get_cache (real_node);
2053
2054 format = gegl_pad_get_format (pad);
2055
2056 if (!format)
2057 {
2058 //g_message ("Output of %s has no format", gegl_node_get_debug_name (node));
2059
2060 format = babl_format ("RGBA float");
2061 }
2062
2063 if (node->cache && gegl_buffer_get_format ((GeglBuffer *)(node->cache)) != format)
2064 g_clear_object (&node->cache);
2065
2066 if (node->cache)
2067 return node->cache;
2068
2069 gegl_node_get_bounding_box (node);
2070
2071 g_mutex_lock (&node->mutex);
2072
2073 if (!node->cache)
2074 {
2075 GeglCache *cache;
2076
2077 cache = g_object_new (
2078 GEGL_TYPE_CACHE,
2079 "format", format,
2080 "initialized", gegl_operation_context_get_init_output (),
2081 NULL);
2082
2083 gegl_object_set_has_forked (G_OBJECT (cache));
2084 gegl_buffer_set_extent (GEGL_BUFFER (cache), &node->have_rect);
2085
2086 g_signal_connect_swapped (G_OBJECT (cache), "computed",
2087 (GCallback) gegl_node_emit_computed,
2088 node);
2089 node->cache = cache;
2090 }
2091
2092 g_mutex_unlock (&node->mutex);
2093
2094 return node->cache;
2095 }
2096
2097 GeglVisitable *
gegl_node_get_output_visitable(GeglNode * self)2098 gegl_node_get_output_visitable (GeglNode *self)
2099 {
2100 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2101
2102 return self->output_visitable;
2103 }
2104
2105 const gchar *
gegl_node_get_name(GeglNode * self)2106 gegl_node_get_name (GeglNode *self)
2107 {
2108 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2109
2110 return self->priv->name;
2111 }
2112
2113 void
gegl_node_set_name(GeglNode * self,const gchar * name)2114 gegl_node_set_name (GeglNode *self,
2115 const gchar *name)
2116 {
2117 g_return_if_fail (GEGL_IS_NODE (self));
2118
2119 g_free (self->priv->name);
2120 self->priv->name = g_strdup (name);
2121
2122 gegl_node_update_debug_name (self);
2123 }
2124
2125 void
gegl_node_remove_children(GeglNode * self)2126 gegl_node_remove_children (GeglNode *self)
2127 {
2128 g_return_if_fail (GEGL_IS_NODE (self));
2129
2130 while (TRUE)
2131 {
2132 GeglNode *child = gegl_node_get_nth_child (self, 0);
2133
2134 if (child && GEGL_IS_NODE (child))
2135 gegl_node_remove_child (self, child);
2136 else
2137 break;
2138 }
2139 }
2140
2141 GeglNode *
gegl_node_add_child(GeglNode * self,GeglNode * child)2142 gegl_node_add_child (GeglNode *self,
2143 GeglNode *child)
2144 {
2145 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2146 g_return_val_if_fail (GEGL_IS_NODE (child), NULL);
2147 g_return_val_if_fail (child->priv->parent == NULL, NULL);
2148
2149 self->priv->children = g_slist_prepend (self->priv->children,
2150 g_object_ref (child));
2151 self->is_graph = TRUE;
2152 child->priv->parent = self;
2153
2154 child->dont_cache = self->dont_cache;
2155 child->cache_policy = self->cache_policy;
2156 child->use_opencl = self->use_opencl;
2157
2158 return child;
2159 }
2160
2161 GeglNode *
gegl_node_remove_child(GeglNode * self,GeglNode * child)2162 gegl_node_remove_child (GeglNode *self,
2163 GeglNode *child)
2164 {
2165 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2166 if (!GEGL_IS_NODE (child))
2167 {
2168 g_print ("%p %s\n", child, G_OBJECT_TYPE_NAME (child));
2169 }
2170 g_return_val_if_fail (GEGL_IS_NODE (child), NULL);
2171
2172 g_assert (child->priv->parent == self ||
2173 child->priv->parent == NULL);
2174
2175 self->priv->children = g_slist_remove (self->priv->children, child);
2176
2177 if (child->priv->parent != NULL)
2178 {
2179 /* if parent isn't set then the node is already in dispose
2180 */
2181 child->priv->parent = NULL;
2182 g_object_unref (child);
2183 }
2184
2185 if (self->priv->children == NULL)
2186 self->is_graph = FALSE;
2187
2188 return child;
2189 }
2190
2191 GeglNode *
gegl_node_get_parent(GeglNode * self)2192 gegl_node_get_parent (GeglNode *self)
2193 {
2194 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2195
2196 return self->priv->parent;
2197 }
2198
2199 gint
gegl_node_get_num_children(GeglNode * self)2200 gegl_node_get_num_children (GeglNode *self)
2201 {
2202 g_return_val_if_fail (GEGL_IS_NODE (self), -1);
2203
2204 return g_slist_length (self->priv->children);
2205 }
2206
2207 GeglNode *
gegl_node_get_nth_child(GeglNode * self,gint n)2208 gegl_node_get_nth_child (GeglNode *self,
2209 gint n)
2210 {
2211 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2212
2213 return g_slist_nth_data (self->priv->children, n);
2214 }
2215
2216 /*
2217 * Returns a copy of the graphs internal list of nodes
2218 */
2219 GSList *
gegl_node_get_children(GeglNode * self)2220 gegl_node_get_children (GeglNode *self)
2221 {
2222 g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
2223
2224 return g_slist_copy (self->priv->children);
2225 }
2226
2227 /*
2228 * returns a freshly created node, owned by the graph, and thus freed with it
2229 */
2230 GeglNode *
gegl_node_new_child(GeglNode * parent,const gchar * first_property_name,...)2231 gegl_node_new_child (GeglNode *parent,
2232 const gchar *first_property_name,
2233 ...)
2234 {
2235 GeglNode *node;
2236 va_list var_args;
2237 const gchar *name;
2238
2239 node = g_object_new (GEGL_TYPE_NODE, NULL);
2240 if (parent)
2241 {
2242 gegl_node_add_child (parent, node);
2243 }
2244
2245 name = first_property_name;
2246 va_start (var_args, first_property_name);
2247 gegl_node_set_valist (node, name, var_args);
2248 va_end (var_args);
2249
2250 if (parent)
2251 g_object_unref (node);
2252 return node;
2253 }
2254
2255 GeglNode *
gegl_node_create_child(GeglNode * self,const gchar * operation)2256 gegl_node_create_child (GeglNode *self,
2257 const gchar *operation)
2258 {
2259 GeglNode *ret;
2260 g_return_val_if_fail (operation != NULL, NULL);
2261
2262 ret = gegl_node_new_child (self, "operation", operation, NULL);
2263 if (ret && self)
2264 {
2265 ret->dont_cache = self->dont_cache;
2266 ret->cache_policy = self->cache_policy;
2267 ret->use_opencl = self->use_opencl;
2268 }
2269 return ret;
2270 }
2271
2272 static void
graph_source_invalidated(GeglNode * source,const GeglRectangle * rect,gpointer data)2273 graph_source_invalidated (GeglNode *source,
2274 const GeglRectangle *rect,
2275 gpointer data)
2276 {
2277 GeglNode *destination = GEGL_NODE (data);
2278 GeglRectangle dirty_rect = *rect;
2279
2280 GEGL_NOTE (GEGL_DEBUG_INVALIDATION, "graph:%s is dirtied from %s (%i,%i %ix%i)",
2281 gegl_node_get_debug_name (destination),
2282 gegl_node_get_debug_name (source),
2283 rect->x, rect->y,
2284 rect->width, rect->height);
2285
2286 gegl_node_invalidated (destination, &dirty_rect, FALSE);
2287 }
2288
2289
2290 static GeglNode *
gegl_node_get_pad_proxy(GeglNode * node,const gchar * name,gboolean is_graph_input)2291 gegl_node_get_pad_proxy (GeglNode *node,
2292 const gchar *name,
2293 gboolean is_graph_input)
2294 {
2295 GeglPad *pad = gegl_node_get_pad (node, name);
2296
2297 if (!pad)
2298 {
2299 GeglNode *nop = NULL;
2300 GeglPad *nop_pad = NULL;
2301 gchar *nop_name = NULL;
2302
2303 nop_name = g_strconcat ("proxynop-", name, NULL);
2304 nop = g_object_new (GEGL_TYPE_NODE, "operation", "gegl:nop", "name", nop_name, NULL);
2305 nop_pad = gegl_node_get_pad (nop, is_graph_input ? "input" : "output");
2306 g_free (nop_name);
2307
2308 gegl_node_add_child (node, nop);
2309 g_object_unref (nop); /* our reference is made by the
2310 gegl_node_add_child call */
2311
2312 {
2313 GeglPad *new_pad = g_object_new (GEGL_TYPE_PAD, NULL);
2314 gegl_pad_set_param_spec (new_pad, nop_pad->param_spec);
2315 gegl_pad_set_node (new_pad, nop);
2316 gegl_pad_set_name (new_pad, name);
2317 gegl_node_add_pad (node, new_pad);
2318 }
2319
2320 g_object_set_data (G_OBJECT (nop), "graph", node);
2321
2322 if (!is_graph_input)
2323 {
2324 g_signal_connect_object (G_OBJECT (nop), "computed",
2325 G_CALLBACK (gegl_node_emit_computed), node,
2326 G_CONNECT_SWAPPED);
2327 g_signal_connect_object (G_OBJECT (nop), "invalidated",
2328 G_CALLBACK (graph_source_invalidated), node,
2329 0);
2330 }
2331 return nop;
2332 }
2333 return gegl_pad_get_node (pad);
2334 }
2335
2336 GeglNode *
gegl_node_get_input_proxy(GeglNode * node,const gchar * name)2337 gegl_node_get_input_proxy (GeglNode *node,
2338 const gchar *name)
2339 {
2340 g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
2341
2342 return gegl_node_get_pad_proxy (node, name, TRUE);
2343 }
2344
2345 GeglNode *
gegl_node_get_output_proxy(GeglNode * node,const gchar * name)2346 gegl_node_get_output_proxy (GeglNode *node,
2347 const gchar *name)
2348 {
2349 g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
2350
2351 return gegl_node_get_pad_proxy (node, name, FALSE);
2352 }
2353
2354 GeglNode *
gegl_node_new(void)2355 gegl_node_new (void)
2356 {
2357 return g_object_new (GEGL_TYPE_NODE, NULL);
2358 }
2359
2360 gboolean
gegl_node_get_passthrough(GeglNode * node)2361 gegl_node_get_passthrough (GeglNode *node)
2362 {
2363 g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
2364
2365 return node->passthrough;
2366 }
2367
2368 void
gegl_node_set_passthrough(GeglNode * node,gboolean passthrough)2369 gegl_node_set_passthrough (GeglNode *node,
2370 gboolean passthrough)
2371 {
2372 g_return_if_fail (GEGL_IS_NODE (node));
2373
2374 if (node->passthrough == passthrough)
2375 return;
2376
2377 node->passthrough = passthrough;
2378 gegl_node_invalidated (node, NULL, TRUE);
2379 }
2380
2381 typedef struct Closure {
2382 GeglNode *node;
2383 gdouble progress;
2384 } Closure;
2385
delayed_emission(void * data)2386 static gboolean delayed_emission (void *data)
2387 {
2388 Closure *closure = data;
2389 g_signal_emit (closure->node,
2390 gegl_node_signals[PROGRESS], 0,
2391 closure->progress, NULL, NULL);
2392 g_free (closure);
2393 return FALSE;
2394 }
2395
2396 /* this causes dispatch of the signal on the main thread - if we
2397 * are in the main thread the callback will be directly executed now
2398 * instead of queued (XXX: and if we're on a different thread, this function is
2399 * a nop -- see comment below.)
2400 */
gegl_node_progress(GeglNode * node,gdouble progress,gchar * message)2401 void gegl_node_progress (GeglNode *node,
2402 gdouble progress,
2403 gchar *message)
2404 {
2405 if (gegl_is_main_thread ())
2406 g_signal_emit (node, gegl_node_signals[PROGRESS], 0, progress, message, NULL);
2407 else
2408 {
2409 /* XXX: only emit the progress signal from the main thread; otherwise, the
2410 * delayed signal may be emitted after the operation is finished, or,
2411 * indeed, after the node is destroyed. for auto-threaded operations, each
2412 * thread tracks its progress independently, so reporting the progress of
2413 * the main thread should be a reasonable estimate of the overall progress.
2414 */
2415 #if 0
2416 Closure *closure = g_new0 (Closure, 1);
2417 closure->node = node;
2418 closure->progress = progress;
2419 g_idle_add (delayed_emission, closure);
2420 #else
2421 (void) delayed_emission;
2422 #endif
2423 }
2424 }
2425
gegl_operation_get_op_version(const char * op_name)2426 const char *gegl_operation_get_op_version (const char *op_name)
2427 {
2428 const gchar *ret = gegl_operation_get_key (op_name, "op-version");
2429 if (!ret)
2430 ret = "0:0";
2431 return ret;
2432 }
2433
2434