static gboolean gimp_operation_mask_components_parent_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation); if (self->mask == 0) { GObject *input = gegl_operation_context_get_object (context, "input"); gegl_operation_context_set_object (context, "output", input); return TRUE; } else if (self->mask == GIMP_COMPONENT_ALL) { GObject *aux = gegl_operation_context_get_object (context, "aux"); gegl_operation_context_set_object (context, "output", aux); return TRUE; } return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, output_prop, result, level); }
/* Fast path when opacity is a no-op */ static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; gpointer in, aux; operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class); /* get the raw values this does not increase the reference count */ in = gegl_operation_context_get_object (context, "input"); aux = gegl_operation_context_get_object (context, "aux"); if (in && !aux && GEGL_CHANT_PROPERTIES (operation)->value == 1.0) { gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
static gboolean gimp_operation_normal_parent_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { #if 0 /* this code tries to be smart but is in fact just a too stupid * copy from gegl's normal mode. to fix it, it needs to take * mask and opacity into account */ const GeglRectangle *in_extent = NULL; const GeglRectangle *aux_extent = NULL; GObject *input; GObject *aux; /* get the raw values this does not increase the reference count */ input = gegl_operation_context_get_object (context, "input"); aux = gegl_operation_context_get_object (context, "aux"); /* pass the input/aux buffers directly through if they are not * overlapping */ if (input) in_extent = gegl_buffer_get_abyss (GEGL_BUFFER (input)); if (! input || (aux && ! gegl_rectangle_intersect (NULL, in_extent, result))) { gegl_operation_context_set_object (context, "output", aux); return TRUE; } if (aux) aux_extent = gegl_buffer_get_abyss (GEGL_BUFFER (aux)); if (! aux || (input && ! gegl_rectangle_intersect (NULL, aux_extent, result))) { gegl_operation_context_set_object (context, "output", input); return TRUE; } #endif /* chain up, which will create the needed buffers for our actual * process function */ return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, output_prop, result, level); }
static gboolean gegl_nop_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglBuffer *input; if (strcmp (output_prop, "output")) { g_warning ("requested processing of %s pad on a nop", output_prop); return FALSE; } input = GEGL_BUFFER (gegl_operation_context_get_object (context, "input")); if (!input) { g_warning ("nop received NULL input"); return FALSE; } gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (input))); return TRUE; }
static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; GeglProperties *o = GEGL_PROPERTIES (operation); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (!o->clip_high && !o->clip_low) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
/* Pass-through when trying to perform IIR on an infinite plane */ static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; GeglProperties *o = GEGL_PROPERTIES (operation); GeglGblur1dFilter filter = filter_disambiguation (o->filter, o->std_dev); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (filter == GEGL_GBLUR_1D_IIR) { const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input"); if (in_rect && gegl_rectangle_is_infinite_plane (in_rect)) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input"); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (in_rect && gegl_rectangle_is_infinite_plane (in_rect)) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
/* Fast paths */ static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; gpointer input, aux; operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class); /* get the raw values this does not increase the reference count */ input = gegl_operation_context_get_object (context, "input"); aux = gegl_operation_context_get_object (context, "aux"); /* pass the input/aux buffers directly through if they are alone*/ { const GeglRectangle *in_extent = NULL; const GeglRectangle *aux_extent = NULL; if (input) in_extent = gegl_buffer_get_abyss (input); if ((!input || (aux && !gegl_rectangle_intersect (NULL, in_extent, result)))) { gegl_operation_context_take_object (context, "output", g_object_ref (aux)); return TRUE; } if (aux) aux_extent = gegl_buffer_get_abyss (aux); if (!aux || (input && !gegl_rectangle_intersect (NULL, aux_extent, result))) { gegl_operation_context_take_object (context, "output", g_object_ref (input)); return TRUE; } } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, level); }
static gboolean photos_operation_svg_multiply_operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_pad, const GeglRectangle *roi, gint level) { GObject *aux; GObject *input; const GeglRectangle *aux_bbox = NULL; const GeglRectangle *in_bbox = NULL; gboolean ret_val = TRUE; aux = gegl_operation_context_get_object (context, "aux"); if (aux != NULL) aux_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (aux)); input = gegl_operation_context_get_object (context, "input"); if (input != NULL) in_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (input)); if (aux == NULL || (input != NULL && !gegl_rectangle_intersect (NULL, aux_bbox, roi))) { gegl_operation_context_set_object (context, "output", input); goto out; } if (input == NULL || (aux != NULL && !gegl_rectangle_intersect (NULL, in_bbox, roi))) { gegl_operation_context_set_object (context, "output", aux); goto out; } ret_val = GEGL_OPERATION_CLASS (photos_operation_svg_multiply_parent_class)->process (operation, context, output_pad, roi, level); out: return ret_val; }
GObject * gegl_operation_context_dup_object (GeglOperationContext *context, const gchar *padname) { GObject *ret; ret = gegl_operation_context_get_object (context, padname); if (ret != NULL) g_object_ref (ret); return ret; }
GeglBuffer * gegl_operation_context_get_source (GeglOperationContext *context, const gchar *padname) { GeglBuffer *real_input; GeglBuffer *input; real_input = GEGL_BUFFER (gegl_operation_context_get_object (context, padname)); if (!real_input) return NULL; input = g_object_ref (real_input); return input; }
static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; GeglProperties *o = GEGL_PROPERTIES (operation); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (! o->radius) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
static gboolean parent_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { if (is_nop (operation)) { GObject *input; input = gegl_operation_context_get_object (context, "input"); gegl_operation_context_set_object (context, "output", input); return TRUE; } return GEGL_OPERATION_CLASS (gegl_op_parent_class)->process (operation, context, output_prop, result, level); }
static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); GeglOperationClass *operation_class; operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class); /* If the profile is NULL, simply become a nop */ if (!o->src_profile) { gpointer input = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (input)); return TRUE; } return operation_class->process (operation, context, output_prop, result, level); }
static gboolean process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); WarpPrivate *priv = (WarpPrivate*) o->user_data; GeglBuffer *input; gdouble spacing = MAX (o->size * o->spacing, 0.5); gdouble dist; gint stamps; gint i; gdouble t; GeglPathPoint prev, next, lerp; GeglPathList *event; WarpPointList *processed_event; WarpPointList **processed_event_ptr; if (!o->stroke || strcmp (output_prop, "output")) return FALSE; /* if the previously processed stroke is valid, the cached buffer can be * passed as output right away. */ if (priv->processed_stroke_valid) { g_assert (priv->buffer != NULL); gegl_operation_context_set_object (context, "output", G_OBJECT (priv->buffer)); return TRUE; } /* ... otherwise, we need to check if the previously processed stroke is an * initial segment of the current stroke ... */ event = gegl_path_get_path (o->stroke); processed_event = priv->processed_stroke; processed_event_ptr = &priv->processed_stroke; while (event && processed_event) { if (event->d.point[0].x != processed_event->point.x || event->d.point[0].y != processed_event->point.y) { break; } processed_event_ptr = &processed_event->next; event = event->next; processed_event = processed_event->next; } /* if the loop stopped before we reached the last event of the processed * stroke, it's not an initial segment, and we need to clear the cache, and * process the entire stroke. */ if (processed_event) { clear_cache (o); event = gegl_path_get_path (o->stroke); processed_event_ptr = &priv->processed_stroke; } /* otherwise, we simply continue processing remaining stroke on top of the * previously processed buffer. */ /* intialize the cached buffer if we don't already have one. */ if (! priv->buffer) { input = GEGL_BUFFER (gegl_operation_context_get_object (context, "input")); priv->buffer = gegl_buffer_dup (input); /* we pass the buffer as output directly while keeping it cached, so mark * it as forked. */ gegl_object_set_has_forked (G_OBJECT (priv->buffer)); } if (event) { /* is this the first event of the stroke? */ if (! priv->processed_stroke) { prev = *(event->d.point); priv->last_x = prev.x; priv->last_y = prev.y; } else { prev.x = priv->last_x; prev.y = priv->last_y; } for (; event; event = event->next) { next = *(event->d.point); dist = gegl_path_point_dist (&next, &prev); stamps = floor (dist / spacing) + 1; /* stroke the current segment, such that there's always a stamp at * its final endpoint, and at positive integer multiples of * `spacing` away from it. */ if (stamps == 1) { stamp (o, next.x, next.y); } else { for (i = 0; i < stamps; i++) { t = 1.0 - ((stamps - i - 1) * spacing) / dist; gegl_path_point_lerp (&lerp, &prev, &next, t); stamp (o, lerp.x, lerp.y); } } prev = next; /* append the current event to the processed path. */ processed_event = g_slice_new (WarpPointList); processed_event->point = next; *processed_event_ptr = processed_event; processed_event_ptr = &processed_event->next; } *processed_event_ptr = NULL; } priv->processed_stroke_valid = TRUE; /* pass the processed buffer as output */ gegl_operation_context_set_object (context, "output", G_OBJECT (priv->buffer)); return TRUE; }
/** * gegl_graph_process: * @path: The traversal path * * Process the prepared request. This will return the * resulting buffer from the final node, or NULL if * that node is a sink. * * If gegl_graph_prepare_request has not been called * the behavior of this function is undefined. * * Return value: (transfer full): The result of the graph, or NULL if * there is no output pad. */ GeglBuffer * gegl_graph_process (GeglGraphTraversal *path, gint level) { GList *list_iter = NULL; GeglBuffer *result = NULL; GeglOperationContext *context = NULL; GeglOperationContext *last_context = NULL; GeglBuffer *operation_result = NULL; for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperation *operation = node->operation; g_return_val_if_fail (node, NULL); g_return_val_if_fail (operation, NULL); GEGL_INSTRUMENT_START(); operation_result = NULL; if (last_context) gegl_operation_context_purge (last_context); context = g_hash_table_lookup (path->contexts, node); g_return_val_if_fail (context, NULL); GEGL_NOTE (GEGL_DEBUG_PROCESS, "Will process %s result_rect = %d, %d %d×%d", gegl_node_get_debug_name (node), context->result_rect.x, context->result_rect.y, context->result_rect.width, context->result_rect.height); if (context->need_rect.width > 0 && context->need_rect.height > 0) { if (context->cached) { GEGL_NOTE (GEGL_DEBUG_PROCESS, "Using cached result for %s", gegl_node_get_debug_name (node)); operation_result = GEGL_BUFFER (node->cache); } else { /* provide something on input pad, always - this makes having behavior depending on it not being set.. not work, is sacrifising that worth it? */ if (gegl_node_has_pad (node, "input") && !gegl_operation_context_get_object (context, "input")) { gegl_operation_context_set_object (context, "input", G_OBJECT (gegl_graph_get_shared_empty(path))); } context->level = level; /* note: this hard-coding of "output" makes some more custom * graph topologies harder than neccesary. */ gegl_operation_process (operation, context, "output", &context->need_rect, context->level); operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output")); if (operation_result && operation_result == (GeglBuffer *)operation->node->cache) gegl_cache_computed (operation->node->cache, &context->need_rect, level); } } else { operation_result = NULL; } if (operation_result) { GeglPad *output_pad = gegl_node_get_pad (node, "output"); GList *targets = gegl_graph_get_connected_output_contexts (path, output_pad); GList *targets_iter; GEGL_NOTE (GEGL_DEBUG_PROCESS, "Will deliver the results of %s:%s to %d targets", gegl_node_get_debug_name (node), "output", g_list_length (targets)); if (g_list_length (targets) > 1) gegl_object_set_has_forked (G_OBJECT (operation_result)); for (targets_iter = targets; targets_iter; targets_iter = g_list_next (targets_iter)) { ContextConnection *target_con = targets_iter->data; gegl_operation_context_set_object (target_con->context, target_con->name, G_OBJECT (operation_result)); } g_list_free_full (targets, free_context_connection); } last_context = context; GEGL_INSTRUMENT_END ("process", gegl_node_get_operation (node)); } if (last_context) { if (operation_result) result = g_object_ref (operation_result); else if (gegl_node_has_pad (last_context->operation->node, "output")) result = g_object_ref (gegl_graph_get_shared_empty (path)); gegl_operation_context_purge (last_context); } return result; }
GeglBuffer * gegl_operation_context_dup_input_maybe_copy (GeglOperationContext *context, const gchar *padname, const GeglRectangle *roi) { GeglBuffer *input; GeglBuffer *output; GeglBuffer *result; GeglRectangle required; GeglRectangle temp; gint shift_x; gint shift_y; gint tile_width; gint tile_height; input = GEGL_BUFFER (gegl_operation_context_get_object (context, padname)); if (! input) return NULL; /* return input directly when processing a level greater than 0, since * gegl_buffer_copy() only copies level-0 tiles */ if (context->level > 0) return g_object_ref (input); output = GEGL_BUFFER (gegl_operation_context_get_object (context, "output")); /* return input directly when processing in-place, otherwise, the copied * input buffer will occupy space in the cache after the original is modified */ if (input == output) return g_object_ref (input); /* get required region to copy */ required = gegl_operation_get_required_for_output (context->operation, padname, roi); /* return input directly if the required rectangle is infinite, so that we * don't attempt to copy an infinite region */ if (gegl_rectangle_is_infinite_plane (&required)) return g_object_ref (input); /* align required region to the tile grid */ shift_x = input->shift_x; shift_y = input->shift_y; tile_width = input->tile_width; tile_height = input->tile_height; temp.x = (gint) floor ((gdouble) (required.x + shift_x) / tile_width) * tile_width; temp.y = (gint) floor ((gdouble) (required.y + shift_y) / tile_height) * tile_height; temp.width = (gint) ceil ((gdouble) (required.x + required.width + shift_x) / tile_width) * tile_width - temp.x; temp.height = (gint) ceil ((gdouble) (required.y + required.height + shift_y) / tile_height) * tile_height - temp.y; temp.x -= shift_x; temp.y -= shift_y; required = temp; /* intersect required region with input abyss */ gegl_rectangle_intersect (&required, &required, &input->abyss); /* create new buffer with similar characteristics to the input buffer */ result = g_object_new (GEGL_TYPE_BUFFER, "format", input->soft_format, "x", input->extent.x, "y", input->extent.y, "width", input->extent.width, "height", input->extent.height, "abyss-x", input->abyss.x, "abyss-y", input->abyss.y, "abyss-width", input->abyss.width, "abyss-height", input->abyss.height, "shift-x", shift_x, "shift-y", shift_y, "tile-width", tile_width, "tile-height", tile_height, NULL); /* if the tile size doesn't match, bail */ if (result->tile_width != tile_width || result->tile_height != tile_height) { g_object_unref (result); return g_object_ref (input); } /* copy required region from input to result -- tiles will generally be COWed */ gegl_buffer_copy (input, &required, GEGL_ABYSS_NONE, result, &required); return result; }