Blame clutter/clutter-path.c

Packit Service bf98b9
/*
Packit Service bf98b9
 * Clutter.
Packit Service bf98b9
 *
Packit Service bf98b9
 * An OpenGL based 'interactive canvas' library.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Authored By Matthew Allum  <mallum@openedhand.com>
Packit Service bf98b9
 *
Packit Service bf98b9
 * Copyright (C) 2008 Intel Corporation
Packit Service bf98b9
 *
Packit Service bf98b9
 * This library is free software; you can redistribute it and/or
Packit Service bf98b9
 * modify it under the terms of the GNU Lesser General Public
Packit Service bf98b9
 * License as published by the Free Software Foundation; either
Packit Service bf98b9
 * version 2 of the License, or (at your option) any later version.
Packit Service bf98b9
 *
Packit Service bf98b9
 * This library is distributed in the hope that it will be useful,
Packit Service bf98b9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service bf98b9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service bf98b9
 * Lesser General Public License for more details.
Packit Service bf98b9
 *
Packit Service bf98b9
 * You should have received a copy of the GNU Lesser General Public
Packit Service bf98b9
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit Service bf98b9
 */
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * SECTION:clutter-path
Packit Service bf98b9
 * @short_description: An object describing a path with straight lines
Packit Service bf98b9
 * and bezier curves.
Packit Service bf98b9
 *
Packit Service bf98b9
 * A #ClutterPath contains a description of a path consisting of
Packit Service bf98b9
 * straight lines and bezier curves. This can be used in a
Packit Service bf98b9
 * #ClutterBehaviourPath to animate an actor moving along the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * The path consists of a series of nodes. Each node is one of the
Packit Service bf98b9
 * following four types:
Packit Service bf98b9
 *
Packit Service bf98b9
 *  - %CLUTTER_PATH_MOVE_TO, changes the position of the path to the
Packit Service bf98b9
 *  given pair of coordinates. This is usually used as the first node
Packit Service bf98b9
 *  of a path to mark the start position. If it is used in the middle
Packit Service bf98b9
 *  of a path then the path will be disjoint and the actor will appear
Packit Service bf98b9
 *  to jump to the new position when animated.
Packit Service bf98b9
 *  - %CLUTTER_PATH_LINE_TO, creates a straight line from the previous
Packit Service bf98b9
 *  point to the given point.
Packit Service bf98b9
 *  - %CLUTTER_PATH_CURVE_TO, creates a bezier curve. The end of the
Packit Service bf98b9
 *  last node is used as the first control point and the three
Packit Service bf98b9
 *  subsequent coordinates given in the node as used as the other three.
Packit Service bf98b9
 *  -%CLUTTER_PATH_CLOSE, creates a straight line from the last node to
Packit Service bf98b9
 *  the last %CLUTTER_PATH_MOVE_TO node. This can be used to close a
Packit Service bf98b9
 *  path so that it will appear as a loop when animated.
Packit Service bf98b9
 *
Packit Service bf98b9
 * The first three types have the corresponding relative versions
Packit Service bf98b9
 * %CLUTTER_PATH_REL_MOVE_TO, %CLUTTER_PATH_REL_LINE_TO and
Packit Service bf98b9
 * %CLUTTER_PATH_REL_CURVE_TO. These are exactly the same except the
Packit Service bf98b9
 * coordinates are given relative to the previous node instead of as
Packit Service bf98b9
 * direct screen positions.
Packit Service bf98b9
 *
Packit Service bf98b9
 * You can build a path using the node adding functions such as
Packit Service bf98b9
 * clutter_path_add_line_to(). Alternatively the path can be described
Packit Service bf98b9
 * in a string using a subset of the SVG path syntax. See
Packit Service bf98b9
 * clutter_path_add_string() for details.
Packit Service bf98b9
 *
Packit Service bf98b9
 * #ClutterPath is available since Clutter 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
Packit Service bf98b9
#ifdef HAVE_CONFIG_H
Packit Service bf98b9
#include "config.h"
Packit Service bf98b9
#endif
Packit Service bf98b9
Packit Service bf98b9
#include <string.h>
Packit Service bf98b9
#include <stdarg.h>
Packit Service bf98b9
#include <math.h>
Packit Service bf98b9
#include <glib-object.h>
Packit Service bf98b9
Packit Service bf98b9
#include "clutter-path.h"
Packit Service bf98b9
#include "clutter-types.h"
Packit Service bf98b9
#include "clutter-bezier.h"
Packit Service bf98b9
#include "clutter-private.h"
Packit Service bf98b9
Packit Service bf98b9
#define CLUTTER_PATH_NODE_TYPE_IS_VALID(t) \
Packit Service bf98b9
  ((((t) & ~CLUTTER_PATH_RELATIVE) >= CLUTTER_PATH_MOVE_TO      \
Packit Service bf98b9
    && ((t) & ~CLUTTER_PATH_RELATIVE) <= CLUTTER_PATH_CURVE_TO) \
Packit Service bf98b9
   || (t) == CLUTTER_PATH_CLOSE)
Packit Service bf98b9
Packit Service bf98b9
enum
Packit Service bf98b9
{
Packit Service bf98b9
  PROP_0,
Packit Service bf98b9
Packit Service bf98b9
  PROP_DESCRIPTION,
Packit Service bf98b9
  PROP_LENGTH,
Packit Service bf98b9
Packit Service bf98b9
  PROP_LAST
Packit Service bf98b9
};
Packit Service bf98b9
Packit Service bf98b9
static GParamSpec *obj_props[PROP_LAST];
Packit Service bf98b9
Packit Service bf98b9
typedef struct _ClutterPathNodeFull ClutterPathNodeFull;
Packit Service bf98b9
Packit Service bf98b9
struct _ClutterPathNodeFull
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathNode k;
Packit Service bf98b9
Packit Service bf98b9
  ClutterBezier *bezier;
Packit Service bf98b9
Packit Service bf98b9
  guint length;
Packit Service bf98b9
};
Packit Service bf98b9
Packit Service bf98b9
struct _ClutterPathPrivate
Packit Service bf98b9
{
Packit Service bf98b9
  GSList *nodes, *nodes_tail;
Packit Service bf98b9
  gboolean nodes_dirty;
Packit Service bf98b9
Packit Service bf98b9
  guint total_length;
Packit Service bf98b9
};
Packit Service bf98b9
Packit Service bf98b9
/* Character tests that don't pay attention to the locale */
Packit Service bf98b9
#define clutter_path_isspace(ch) memchr (" \f\n\r\t\v", (ch), 6)
Packit Service bf98b9
#define clutter_path_isdigit(ch) ((ch) >= '0' && (ch) <= '9')
Packit Service bf98b9
Packit Service bf98b9
static ClutterPathNodeFull *clutter_path_node_full_new (void);
Packit Service bf98b9
static void clutter_path_node_full_free (ClutterPathNodeFull *node);
Packit Service bf98b9
Packit Service bf98b9
static void clutter_path_finalize (GObject *object);
Packit Service bf98b9
Packit Service bf98b9
static void clutter_value_transform_path_string (const GValue *src,
Packit Service bf98b9
                                                 GValue       *dest);
Packit Service bf98b9
static void clutter_value_transform_string_path (const GValue *src,
Packit Service bf98b9
                                                 GValue       *dest);
Packit Service bf98b9
Packit Service bf98b9
G_DEFINE_BOXED_TYPE (ClutterPathNode, clutter_path_node,
Packit Service bf98b9
                     clutter_path_node_copy,
Packit Service bf98b9
                     clutter_path_node_free);
Packit Service bf98b9
Packit Service bf98b9
G_DEFINE_TYPE_WITH_CODE (ClutterPath,
Packit Service bf98b9
                         clutter_path,
Packit Service bf98b9
                         G_TYPE_INITIALLY_UNOWNED,
Packit Service bf98b9
                         G_ADD_PRIVATE (ClutterPath)
Packit Service bf98b9
                         CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_STRING, clutter_value_transform_path_string)
Packit Service bf98b9
                         CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_STRING, clutter_value_transform_string_path));
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_get_property (GObject      *gobject,
Packit Service bf98b9
                           guint         prop_id,
Packit Service bf98b9
                           GValue       *value,
Packit Service bf98b9
                           GParamSpec   *pspec)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPath *path = CLUTTER_PATH (gobject);
Packit Service bf98b9
Packit Service bf98b9
  switch (prop_id)
Packit Service bf98b9
    {
Packit Service bf98b9
    case PROP_DESCRIPTION:
Packit Service bf98b9
      g_value_take_string (value, clutter_path_get_description (path));
Packit Service bf98b9
      break;
Packit Service bf98b9
    case PROP_LENGTH:
Packit Service bf98b9
      g_value_set_uint (value, clutter_path_get_length (path));
Packit Service bf98b9
      break;
Packit Service bf98b9
    default:
Packit Service bf98b9
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit Service bf98b9
      break;
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_set_property (GObject      *gobject,
Packit Service bf98b9
                           guint         prop_id,
Packit Service bf98b9
                           const GValue *value,
Packit Service bf98b9
                           GParamSpec   *pspec)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPath *path = CLUTTER_PATH (gobject);
Packit Service bf98b9
Packit Service bf98b9
  switch (prop_id)
Packit Service bf98b9
    {
Packit Service bf98b9
    case PROP_DESCRIPTION:
Packit Service bf98b9
      if (!clutter_path_set_description (path, g_value_get_string (value)))
Packit Service bf98b9
        g_warning ("Invalid path description");
Packit Service bf98b9
      break;
Packit Service bf98b9
    default:
Packit Service bf98b9
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit Service bf98b9
      break;
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_class_init (ClutterPathClass *klass)
Packit Service bf98b9
{
Packit Service bf98b9
  GObjectClass *gobject_class = (GObjectClass *) klass;
Packit Service bf98b9
  GParamSpec *pspec;
Packit Service bf98b9
Packit Service bf98b9
  gobject_class->get_property = clutter_path_get_property;
Packit Service bf98b9
  gobject_class->set_property = clutter_path_set_property;
Packit Service bf98b9
  gobject_class->finalize = clutter_path_finalize;
Packit Service bf98b9
Packit Service bf98b9
  pspec = g_param_spec_string ("description",
Packit Service bf98b9
                               "Description",
Packit Service bf98b9
                               "SVG-style description of the path",
Packit Service bf98b9
                               "",
Packit Service bf98b9
                               CLUTTER_PARAM_READWRITE);
Packit Service bf98b9
  obj_props[PROP_DESCRIPTION] = pspec;
Packit Service bf98b9
  g_object_class_install_property (gobject_class, PROP_DESCRIPTION, pspec);
Packit Service bf98b9
Packit Service bf98b9
  pspec = g_param_spec_uint ("length",
Packit Service bf98b9
                             "Length",
Packit Service bf98b9
                             "An approximation of the total length "
Packit Service bf98b9
                             "of the path.",
Packit Service bf98b9
                             0, G_MAXUINT, 0,
Packit Service bf98b9
                             CLUTTER_PARAM_READABLE);
Packit Service bf98b9
  obj_props[PROP_LENGTH] = pspec;
Packit Service bf98b9
  g_object_class_install_property (gobject_class, PROP_LENGTH, pspec);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_init (ClutterPath *self)
Packit Service bf98b9
{
Packit Service bf98b9
  self->priv = clutter_path_get_instance_private (self);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_value_transform_path_string (const GValue *src,
Packit Service bf98b9
                                     GValue       *dest)
Packit Service bf98b9
{
Packit Service bf98b9
  gchar *string = clutter_path_get_description (src->data[0].v_pointer);
Packit Service bf98b9
Packit Service bf98b9
  g_value_take_string (dest, string);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_value_transform_string_path (const GValue *src,
Packit Service bf98b9
                                     GValue       *dest)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPath *new_path;
Packit Service bf98b9
Packit Service bf98b9
  new_path = clutter_path_new_with_description (g_value_get_string (src));
Packit Service bf98b9
  g_value_take_object (dest, new_path);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_finalize (GObject *object)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPath *self = (ClutterPath *) object;
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_clear (self);
Packit Service bf98b9
Packit Service bf98b9
  G_OBJECT_CLASS (clutter_path_parent_class)->finalize (object);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_new:
Packit Service bf98b9
 *
Packit Service bf98b9
 * Creates a new #ClutterPath instance with no nodes.
Packit Service bf98b9
 *
Packit Service bf98b9
 * The object has a floating reference so if you add it to a
Packit Service bf98b9
 * #ClutterBehaviourPath then you do not need to unref it.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the newly created #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
ClutterPath *
Packit Service bf98b9
clutter_path_new (void)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPath *self = g_object_new (CLUTTER_TYPE_PATH, NULL);
Packit Service bf98b9
Packit Service bf98b9
  return self;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_new_with_description:
Packit Service bf98b9
 * @desc: a string describing the path
Packit Service bf98b9
 *
Packit Service bf98b9
 * Creates a new #ClutterPath instance with the nodes described in
Packit Service bf98b9
 * @desc. See clutter_path_add_string() for details of the format of
Packit Service bf98b9
 * the string.
Packit Service bf98b9
 *
Packit Service bf98b9
 * The object has a floating reference so if you add it to a
Packit Service bf98b9
 * #ClutterBehaviourPath then you do not need to unref it.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the newly created #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
ClutterPath *
Packit Service bf98b9
clutter_path_new_with_description (const gchar *desc)
Packit Service bf98b9
{
Packit Service bf98b9
  return g_object_new (CLUTTER_TYPE_PATH,
Packit Service bf98b9
                       "description", desc,
Packit Service bf98b9
                       NULL);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_clear:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Removes all nodes from the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_clear (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  g_slist_foreach (priv->nodes, (GFunc) clutter_path_node_full_free, NULL);
Packit Service bf98b9
  g_slist_free (priv->nodes);
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes = priv->nodes_tail = NULL;
Packit Service bf98b9
  priv->nodes_dirty = TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/* Takes ownership of the node */
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_add_node_full (ClutterPath         *path,
Packit Service bf98b9
                            ClutterPathNodeFull *node)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv = path->priv;
Packit Service bf98b9
  GSList *new_node;
Packit Service bf98b9
Packit Service bf98b9
  new_node = g_slist_prepend (NULL, node);
Packit Service bf98b9
Packit Service bf98b9
  if (priv->nodes_tail == NULL)
Packit Service bf98b9
    priv->nodes = new_node;
Packit Service bf98b9
  else
Packit Service bf98b9
    priv->nodes_tail->next = new_node;
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes_tail = new_node;
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes_dirty = TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/* Helper function to make the rest of teh add_* functions shorter */
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_add_node_helper (ClutterPath         *path,
Packit Service bf98b9
                              ClutterPathNodeType  type,
Packit Service bf98b9
                              int                  num_coords,
Packit Service bf98b9
                              ...)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathNodeFull *node;
Packit Service bf98b9
  int i;
Packit Service bf98b9
  va_list ap;
Packit Service bf98b9
Packit Service bf98b9
  node = clutter_path_node_full_new ();
Packit Service bf98b9
Packit Service bf98b9
  node->k.type = type;
Packit Service bf98b9
Packit Service bf98b9
  va_start (ap, num_coords);
Packit Service bf98b9
Packit Service bf98b9
  for (i = 0; i < num_coords; i++)
Packit Service bf98b9
    {
Packit Service bf98b9
      node->k.points[i].x = va_arg (ap, gint);
Packit Service bf98b9
      node->k.points[i].y = va_arg (ap, gint);
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  va_end (ap);
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_full (path, node);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_move_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x: the x coordinate
Packit Service bf98b9
 * @y: the y coordinate
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds a %CLUTTER_PATH_MOVE_TO type node to the path. This is usually
Packit Service bf98b9
 * used as the first node in a path. It can also be used in the middle
Packit Service bf98b9
 * of the path to cause the actor to jump to the new coordinate.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_move_to (ClutterPath *path,
Packit Service bf98b9
                          gint         x,
Packit Service bf98b9
                          gint         y)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_MOVE_TO, 1, x, y);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_rel_move_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x: the x coordinate
Packit Service bf98b9
 * @y: the y coordinate
Packit Service bf98b9
 *
Packit Service bf98b9
 * Same as clutter_path_add_move_to() except the coordinates are
Packit Service bf98b9
 * relative to the previous node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_rel_move_to (ClutterPath *path,
Packit Service bf98b9
                              gint         x,
Packit Service bf98b9
                              gint         y)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_REL_MOVE_TO, 1, x, y);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_line_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x: the x coordinate
Packit Service bf98b9
 * @y: the y coordinate
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds a %CLUTTER_PATH_LINE_TO type node to the path. This causes the
Packit Service bf98b9
 * actor to move to the new coordinates in a straight line.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_line_to (ClutterPath *path,
Packit Service bf98b9
                          gint         x,
Packit Service bf98b9
                          gint         y)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_LINE_TO, 1, x, y);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_rel_line_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x: the x coordinate
Packit Service bf98b9
 * @y: the y coordinate
Packit Service bf98b9
 *
Packit Service bf98b9
 * Same as clutter_path_add_line_to() except the coordinates are
Packit Service bf98b9
 * relative to the previous node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_rel_line_to (ClutterPath *path,
Packit Service bf98b9
                              gint         x,
Packit Service bf98b9
                              gint         y)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_REL_LINE_TO, 1, x, y);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_curve_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x_1: the x coordinate of the first control point
Packit Service bf98b9
 * @y_1: the y coordinate of the first control point
Packit Service bf98b9
 * @x_2: the x coordinate of the second control point
Packit Service bf98b9
 * @y_2: the y coordinate of the second control point
Packit Service bf98b9
 * @x_3: the x coordinate of the third control point
Packit Service bf98b9
 * @y_3: the y coordinate of the third control point
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds a %CLUTTER_PATH_CURVE_TO type node to the path. This causes
Packit Service bf98b9
 * the actor to follow a bezier from the last node to (@x_3, @y_3) using
Packit Service bf98b9
 * (@x_1, @y_1) and (@x_2,@y_2) as control points.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_curve_to (ClutterPath *path,
Packit Service bf98b9
                           gint         x_1,
Packit Service bf98b9
                           gint         y_1,
Packit Service bf98b9
                           gint         x_2,
Packit Service bf98b9
                           gint         y_2,
Packit Service bf98b9
                           gint         x_3,
Packit Service bf98b9
                           gint         y_3)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_CURVE_TO, 3,
Packit Service bf98b9
                                x_1, y_1,
Packit Service bf98b9
                                x_2, y_2,
Packit Service bf98b9
                                x_3, y_3);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_rel_curve_to:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @x_1: the x coordinate of the first control point
Packit Service bf98b9
 * @y_1: the y coordinate of the first control point
Packit Service bf98b9
 * @x_2: the x coordinate of the second control point
Packit Service bf98b9
 * @y_2: the y coordinate of the second control point
Packit Service bf98b9
 * @x_3: the x coordinate of the third control point
Packit Service bf98b9
 * @y_3: the y coordinate of the third control point
Packit Service bf98b9
 *
Packit Service bf98b9
 * Same as clutter_path_add_curve_to() except the coordinates are
Packit Service bf98b9
 * relative to the previous node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_rel_curve_to (ClutterPath *path,
Packit Service bf98b9
                               gint         x_1,
Packit Service bf98b9
                               gint         y_1,
Packit Service bf98b9
                               gint         x_2,
Packit Service bf98b9
                               gint         y_2,
Packit Service bf98b9
                               gint         x_3,
Packit Service bf98b9
                               gint         y_3)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_REL_CURVE_TO, 3,
Packit Service bf98b9
                                x_1, y_1,
Packit Service bf98b9
                                x_2, y_2,
Packit Service bf98b9
                                x_3, y_3);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_close:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds a %CLUTTER_PATH_CLOSE type node to the path. This creates a
Packit Service bf98b9
 * straight line from the last node to the last %CLUTTER_PATH_MOVE_TO
Packit Service bf98b9
 * type node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_close (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_helper (path, CLUTTER_PATH_CLOSE, 0);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static gboolean
Packit Service bf98b9
clutter_path_parse_number (const gchar **pin,
Packit Service bf98b9
                           gboolean      allow_comma,
Packit Service bf98b9
                           gint         *ret)
Packit Service bf98b9
{
Packit Service bf98b9
  gint val = 0;
Packit Service bf98b9
  gboolean negative = FALSE;
Packit Service bf98b9
  gint digit_count = 0;
Packit Service bf98b9
  const gchar *p = *pin;
Packit Service bf98b9
Packit Service bf98b9
  /* Skip leading spaces */
Packit Service bf98b9
  while (clutter_path_isspace (*p))
Packit Service bf98b9
    p++;
Packit Service bf98b9
Packit Service bf98b9
  /* Optional comma */
Packit Service bf98b9
  if (allow_comma && *p == ',')
Packit Service bf98b9
    {
Packit Service bf98b9
      p++;
Packit Service bf98b9
      while (clutter_path_isspace (*p))
Packit Service bf98b9
        p++;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  /* Optional sign */
Packit Service bf98b9
  if (*p == '+')
Packit Service bf98b9
    p++;
Packit Service bf98b9
  else if (*p == '-')
Packit Service bf98b9
    {
Packit Service bf98b9
      negative = TRUE;
Packit Service bf98b9
      p++;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  /* Some digits */
Packit Service bf98b9
  while (clutter_path_isdigit (*p))
Packit Service bf98b9
    {
Packit Service bf98b9
      val = val * 10 + *p - '0';
Packit Service bf98b9
      digit_count++;
Packit Service bf98b9
      p++;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  /* We need at least one digit */
Packit Service bf98b9
  if (digit_count < 1)
Packit Service bf98b9
    return FALSE;
Packit Service bf98b9
Packit Service bf98b9
  /* Optional fractional part which we ignore */
Packit Service bf98b9
  if (*p == '.')
Packit Service bf98b9
    {
Packit Service bf98b9
      p++;
Packit Service bf98b9
      digit_count = 0;
Packit Service bf98b9
      while (clutter_path_isdigit (*p))
Packit Service bf98b9
        {
Packit Service bf98b9
          digit_count++;
Packit Service bf98b9
          p++;
Packit Service bf98b9
        }
Packit Service bf98b9
      /* If there is a fractional part then it also needs at least one
Packit Service bf98b9
         digit */
Packit Service bf98b9
      if (digit_count < 1)
Packit Service bf98b9
        return FALSE;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  *pin = p;
Packit Service bf98b9
  *ret = negative ? -val : val;
Packit Service bf98b9
Packit Service bf98b9
  return TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static gboolean
Packit Service bf98b9
clutter_path_parse_description (const gchar  *p,
Packit Service bf98b9
                                GSList      **ret)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathNodeFull *node;
Packit Service bf98b9
  GSList *nodes = NULL;
Packit Service bf98b9
Packit Service bf98b9
  if (p == NULL || *p == '\0')
Packit Service bf98b9
    return FALSE;
Packit Service bf98b9
Packit Service bf98b9
  while (TRUE)
Packit Service bf98b9
    {
Packit Service bf98b9
      /* Skip leading whitespace */
Packit Service bf98b9
      while (clutter_path_isspace (*p))
Packit Service bf98b9
        p++;
Packit Service bf98b9
Packit Service bf98b9
      /* It is not an error to end now */
Packit Service bf98b9
      if (*p == '\0')
Packit Service bf98b9
        break;
Packit Service bf98b9
Packit Service bf98b9
      switch (*p)
Packit Service bf98b9
        {
Packit Service bf98b9
        case 'M':
Packit Service bf98b9
        case 'm':
Packit Service bf98b9
        case 'L':
Packit Service bf98b9
        case 'l':
Packit Service bf98b9
          node = clutter_path_node_full_new ();
Packit Service bf98b9
          nodes = g_slist_prepend (nodes, node);
Packit Service bf98b9
Packit Service bf98b9
          node->k.type = (*p == 'M' ? CLUTTER_PATH_MOVE_TO :
Packit Service bf98b9
                          *p == 'm' ? CLUTTER_PATH_REL_MOVE_TO :
Packit Service bf98b9
                          *p == 'L' ? CLUTTER_PATH_LINE_TO :
Packit Service bf98b9
                          CLUTTER_PATH_REL_LINE_TO);
Packit Service bf98b9
          p++;
Packit Service bf98b9
Packit Service bf98b9
          if (!clutter_path_parse_number (&p, FALSE, &node->k.points[0].x) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[0].y))
Packit Service bf98b9
            goto fail;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case 'C':
Packit Service bf98b9
        case 'c':
Packit Service bf98b9
          node = clutter_path_node_full_new ();
Packit Service bf98b9
          nodes = g_slist_prepend (nodes, node);
Packit Service bf98b9
Packit Service bf98b9
          node->k.type = (*p == 'C' ? CLUTTER_PATH_CURVE_TO :
Packit Service bf98b9
                          CLUTTER_PATH_REL_CURVE_TO);
Packit Service bf98b9
          p++;
Packit Service bf98b9
Packit Service bf98b9
          if (!clutter_path_parse_number (&p, FALSE, &node->k.points[0].x) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[0].y) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[1].x) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[1].y) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[2].x) ||
Packit Service bf98b9
              !clutter_path_parse_number (&p, TRUE, &node->k.points[2].y))
Packit Service bf98b9
            goto fail;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case 'Z':
Packit Service bf98b9
        case 'z':
Packit Service bf98b9
          node = clutter_path_node_full_new ();
Packit Service bf98b9
          nodes = g_slist_prepend (nodes, node);
Packit Service bf98b9
          p++;
Packit Service bf98b9
Packit Service bf98b9
          node->k.type = CLUTTER_PATH_CLOSE;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        default:
Packit Service bf98b9
          goto fail;
Packit Service bf98b9
        }
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  *ret = g_slist_reverse (nodes);
Packit Service bf98b9
  return TRUE;
Packit Service bf98b9
Packit Service bf98b9
 fail:
Packit Service bf98b9
  g_slist_foreach (nodes, (GFunc) clutter_path_node_full_free, NULL);
Packit Service bf98b9
  g_slist_free (nodes);
Packit Service bf98b9
  return FALSE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/* Takes ownership of the node list */
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_add_nodes (ClutterPath *path,
Packit Service bf98b9
                        GSList      *nodes)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  if (priv->nodes_tail == NULL)
Packit Service bf98b9
    priv->nodes = nodes;
Packit Service bf98b9
  else
Packit Service bf98b9
    priv->nodes_tail->next = nodes;
Packit Service bf98b9
Packit Service bf98b9
  while (nodes)
Packit Service bf98b9
    {
Packit Service bf98b9
      priv->nodes_tail = nodes;
Packit Service bf98b9
      nodes = nodes->next;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes_dirty = TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_string:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @str: a string describing the new nodes
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds new nodes to the end of the path as described in @str. The
Packit Service bf98b9
 * format is a subset of the SVG path format. Each node is represented
Packit Service bf98b9
 * by a letter and is followed by zero, one or three pairs of
Packit Service bf98b9
 * coordinates. The coordinates can be separated by spaces or a
Packit Service bf98b9
 * comma. The types are:
Packit Service bf98b9
 *
Packit Service bf98b9
 *  - `M`: Adds a %CLUTTER_PATH_MOVE_TO node. Takes one pair of coordinates.
Packit Service bf98b9
 *  - `L`: Adds a %CLUTTER_PATH_LINE_TO node. Takes one pair of coordinates.
Packit Service bf98b9
 *  - `C`: Adds a %CLUTTER_PATH_CURVE_TO node. Takes three pairs of coordinates.
Packit Service bf98b9
 *  - `z`: Adds a %CLUTTER_PATH_CLOSE node. No coordinates are needed.
Packit Service bf98b9
 *
Packit Service bf98b9
 * The M, L and C commands can also be specified in lower case which
Packit Service bf98b9
 * means the coordinates are relative to the previous node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * For example, to move an actor in a 100 by 100 pixel square centered
Packit Service bf98b9
 * on the point 300,300 you could use the following path:
Packit Service bf98b9
 *
Packit Service bf98b9
 * |[
Packit Service bf98b9
 *   M 250,350 l 0 -100 L 350,250 l 0 100 z
Packit Service bf98b9
 * ]|
Packit Service bf98b9
 *
Packit Service bf98b9
 * If the path description isn't valid %FALSE will be returned and no
Packit Service bf98b9
 * nodes will be added.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: %TRUE is the path description was valid or %FALSE
Packit Service bf98b9
 * otherwise.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
gboolean
Packit Service bf98b9
clutter_path_add_string (ClutterPath *path,
Packit Service bf98b9
                         const gchar *str)
Packit Service bf98b9
{
Packit Service bf98b9
  GSList *nodes;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), FALSE);
Packit Service bf98b9
  g_return_val_if_fail (str != NULL, FALSE);
Packit Service bf98b9
Packit Service bf98b9
  if (clutter_path_parse_description (str, &nodes))
Packit Service bf98b9
    {
Packit Service bf98b9
      clutter_path_add_nodes (path, nodes);
Packit Service bf98b9
Packit Service bf98b9
      return TRUE;
Packit Service bf98b9
    }
Packit Service bf98b9
  else
Packit Service bf98b9
    return FALSE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_node:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @node: a #ClutterPathNode
Packit Service bf98b9
 *
Packit Service bf98b9
 * Adds @node to the end of the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_node (ClutterPath           *path,
Packit Service bf98b9
                       const ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathNodeFull *node_full;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
  g_return_if_fail (node != NULL);
Packit Service bf98b9
  g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type));
Packit Service bf98b9
Packit Service bf98b9
  node_full = clutter_path_node_full_new ();
Packit Service bf98b9
  node_full->k = *node;
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_add_node_full (path, node_full);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_add_cairo_path:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @cpath: a Cairo path
Packit Service bf98b9
 *
Packit Service bf98b9
 * Add the nodes of the Cairo path to the end of @path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_add_cairo_path (ClutterPath        *path,
Packit Service bf98b9
                             const cairo_path_t *cpath)
Packit Service bf98b9
{
Packit Service bf98b9
  int num_data;
Packit Service bf98b9
  const cairo_path_data_t *p;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
  g_return_if_fail (cpath != NULL);
Packit Service bf98b9
Packit Service bf98b9
  /* Iterate over each command in the cairo path */
Packit Service bf98b9
  for (num_data = cpath->num_data, p = cpath->data;
Packit Service bf98b9
       num_data > 0;
Packit Service bf98b9
       num_data -= p->header.length, p += p->header.length)
Packit Service bf98b9
    {
Packit Service bf98b9
      switch (p->header.type)
Packit Service bf98b9
        {
Packit Service bf98b9
        case CAIRO_PATH_MOVE_TO:
Packit Service bf98b9
          g_assert (p->header.length >= 2);
Packit Service bf98b9
Packit Service bf98b9
          clutter_path_add_move_to (path, p[1].point.x, p[1].point.y);
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CAIRO_PATH_LINE_TO:
Packit Service bf98b9
          g_assert (p->header.length >= 2);
Packit Service bf98b9
Packit Service bf98b9
          clutter_path_add_line_to (path, p[1].point.x, p[1].point.y);
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CAIRO_PATH_CURVE_TO:
Packit Service bf98b9
          g_assert (p->header.length >= 4);
Packit Service bf98b9
Packit Service bf98b9
          clutter_path_add_curve_to (path,
Packit Service bf98b9
                                     p[1].point.x, p[1].point.y,
Packit Service bf98b9
                                     p[2].point.x, p[2].point.y,
Packit Service bf98b9
                                     p[3].point.x, p[3].point.y);
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CAIRO_PATH_CLOSE_PATH:
Packit Service bf98b9
          clutter_path_add_close (path);
Packit Service bf98b9
        }
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_add_node_to_cairo_path (const ClutterPathNode *node,
Packit Service bf98b9
                                     gpointer               data)
Packit Service bf98b9
{
Packit Service bf98b9
  cairo_t *cr = data;
Packit Service bf98b9
Packit Service bf98b9
  switch (node->type)
Packit Service bf98b9
    {
Packit Service bf98b9
    case CLUTTER_PATH_MOVE_TO:
Packit Service bf98b9
      cairo_move_to (cr, node->points[0].x, node->points[0].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_LINE_TO:
Packit Service bf98b9
      cairo_line_to (cr, node->points[0].x, node->points[0].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_CURVE_TO:
Packit Service bf98b9
      cairo_curve_to (cr,
Packit Service bf98b9
                      node->points[0].x, node->points[0].y,
Packit Service bf98b9
                      node->points[1].x, node->points[1].y,
Packit Service bf98b9
                      node->points[2].x, node->points[2].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_REL_MOVE_TO:
Packit Service bf98b9
      cairo_rel_move_to (cr, node->points[0].x, node->points[0].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_REL_LINE_TO:
Packit Service bf98b9
      cairo_rel_line_to (cr, node->points[0].x, node->points[0].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_REL_CURVE_TO:
Packit Service bf98b9
      cairo_rel_curve_to (cr,
Packit Service bf98b9
                          node->points[0].x, node->points[0].y,
Packit Service bf98b9
                          node->points[1].x, node->points[1].y,
Packit Service bf98b9
                          node->points[2].x, node->points[2].y);
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_CLOSE:
Packit Service bf98b9
      cairo_close_path (cr);
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_to_cairo_path:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @cr: a Cairo context
Packit Service bf98b9
 *
Packit Service bf98b9
 * Add the nodes of the ClutterPath to the path in the Cairo context.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_to_cairo_path (ClutterPath *path,
Packit Service bf98b9
                            cairo_t     *cr)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
  g_return_if_fail (cr != NULL);
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_foreach (path, clutter_path_add_node_to_cairo_path, cr);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_n_nodes:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Retrieves the number of nodes in the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the number of nodes.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
guint
Packit Service bf98b9
clutter_path_get_n_nodes (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), 0);
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  return g_slist_length (priv->nodes);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_node:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @index_: the node number to retrieve
Packit Service bf98b9
 * @node: (out): a location to store a copy of the node
Packit Service bf98b9
 *
Packit Service bf98b9
 * Retrieves the node of the path indexed by @index.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_get_node (ClutterPath     *path,
Packit Service bf98b9
                       guint            index_,
Packit Service bf98b9
                       ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathNodeFull *node_full;
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  node_full = g_slist_nth_data (priv->nodes, index_);
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (node_full != NULL);
Packit Service bf98b9
Packit Service bf98b9
  *node = node_full->k;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_nodes:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Returns a #GSList of #ClutterPathNodes. The list should be
Packit Service bf98b9
 * freed with g_slist_free(). The nodes are owned by the path and
Packit Service bf98b9
 * should not be freed. Altering the path may cause the nodes in the
Packit Service bf98b9
 * list to become invalid so you should copy them if you want to keep
Packit Service bf98b9
 * the list.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: (transfer container) (element-type Clutter.PathNode): a
Packit Service bf98b9
 *   list of nodes in the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
GSList *
Packit Service bf98b9
clutter_path_get_nodes (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), NULL);
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  return g_slist_copy (priv->nodes);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_foreach:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @callback: (scope call): the function to call with each node
Packit Service bf98b9
 * @user_data: user data to pass to the function
Packit Service bf98b9
 *
Packit Service bf98b9
 * Calls a function for each node of the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_foreach (ClutterPath         *path,
Packit Service bf98b9
                      ClutterPathCallback  callback,
Packit Service bf98b9
                      gpointer             user_data)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  g_slist_foreach (priv->nodes, (GFunc) callback, user_data);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_insert_node:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @index_: offset of where to insert the node
Packit Service bf98b9
 * @node: the node to insert
Packit Service bf98b9
 *
Packit Service bf98b9
 * Inserts @node into the path before the node at the given offset. If
Packit Service bf98b9
 * @index_ is negative it will append the node to the end of the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_insert_node (ClutterPath           *path,
Packit Service bf98b9
                          gint                   index_,
Packit Service bf98b9
                          const ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
  ClutterPathNodeFull *node_full;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
  g_return_if_fail (node != NULL);
Packit Service bf98b9
  g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type));
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  node_full = clutter_path_node_full_new ();
Packit Service bf98b9
  node_full->k = *node;
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes = g_slist_insert (priv->nodes, node_full, index_);
Packit Service bf98b9
Packit Service bf98b9
  if (priv->nodes_tail == NULL)
Packit Service bf98b9
    priv->nodes_tail = priv->nodes;
Packit Service bf98b9
  else if (priv->nodes_tail->next)
Packit Service bf98b9
    priv->nodes_tail = priv->nodes_tail->next;
Packit Service bf98b9
Packit Service bf98b9
  priv->nodes_dirty = TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_remove_node:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @index_: index of the node to remove
Packit Service bf98b9
 *
Packit Service bf98b9
 * Removes the node at the given offset from the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_remove_node (ClutterPath *path,
Packit Service bf98b9
                          guint        index_)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
  GSList *node, *prev = NULL;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  for (node = priv->nodes; node && index_--; node = node->next)
Packit Service bf98b9
    prev = node;
Packit Service bf98b9
Packit Service bf98b9
  if (node)
Packit Service bf98b9
    {
Packit Service bf98b9
      clutter_path_node_full_free (node->data);
Packit Service bf98b9
Packit Service bf98b9
      if (prev)
Packit Service bf98b9
        prev->next = node->next;
Packit Service bf98b9
      else
Packit Service bf98b9
        priv->nodes = node->next;
Packit Service bf98b9
Packit Service bf98b9
      if (node == priv->nodes_tail)
Packit Service bf98b9
        priv->nodes_tail = prev;
Packit Service bf98b9
Packit Service bf98b9
      g_slist_free_1 (node);
Packit Service bf98b9
Packit Service bf98b9
      priv->nodes_dirty = TRUE;
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_replace_node:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @index_: index to the existing node
Packit Service bf98b9
 * @node: the replacement node
Packit Service bf98b9
 *
Packit Service bf98b9
 * Replaces the node at offset @index_ with @node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_replace_node (ClutterPath           *path,
Packit Service bf98b9
                           guint                  index_,
Packit Service bf98b9
                           const ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
  ClutterPathNodeFull *node_full;
Packit Service bf98b9
Packit Service bf98b9
  g_return_if_fail (CLUTTER_IS_PATH (path));
Packit Service bf98b9
  g_return_if_fail (node != NULL);
Packit Service bf98b9
  g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type));
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  if ((node_full = g_slist_nth_data (priv->nodes, index_)))
Packit Service bf98b9
    {
Packit Service bf98b9
      node_full->k = *node;
Packit Service bf98b9
Packit Service bf98b9
      priv->nodes_dirty = TRUE;
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_set_description:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @str: a string describing the path
Packit Service bf98b9
 *
Packit Service bf98b9
 * Replaces all of the nodes in the path with nodes described by
Packit Service bf98b9
 * @str. See clutter_path_add_string() for details of the format.
Packit Service bf98b9
 *
Packit Service bf98b9
 * If the string is invalid then %FALSE is returned and the path is
Packit Service bf98b9
 * unaltered.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: %TRUE is the path was valid, %FALSE otherwise.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
gboolean
Packit Service bf98b9
clutter_path_set_description (ClutterPath *path,
Packit Service bf98b9
                              const gchar *str)
Packit Service bf98b9
{
Packit Service bf98b9
  GSList *nodes;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), FALSE);
Packit Service bf98b9
  g_return_val_if_fail (str != NULL, FALSE);
Packit Service bf98b9
Packit Service bf98b9
  if (clutter_path_parse_description (str, &nodes))
Packit Service bf98b9
    {
Packit Service bf98b9
      clutter_path_clear (path);
Packit Service bf98b9
      clutter_path_add_nodes (path, nodes);
Packit Service bf98b9
Packit Service bf98b9
      return TRUE;
Packit Service bf98b9
    }
Packit Service bf98b9
  else
Packit Service bf98b9
    return FALSE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_description:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Returns a newly allocated string describing the path in the same
Packit Service bf98b9
 * format as used by clutter_path_add_string().
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: a string description of the path. Free with g_free().
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
gchar *
Packit Service bf98b9
clutter_path_get_description (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
  GString *str;
Packit Service bf98b9
  GSList *l;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), NULL);
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  str = g_string_new ("");
Packit Service bf98b9
Packit Service bf98b9
  for (l = priv->nodes; l; l = l->next)
Packit Service bf98b9
    {
Packit Service bf98b9
      ClutterPathNodeFull *node = l->data;
Packit Service bf98b9
      gchar letter = '?';
Packit Service bf98b9
      gint params = 0;
Packit Service bf98b9
      gint i;
Packit Service bf98b9
Packit Service bf98b9
      switch (node->k.type)
Packit Service bf98b9
        {
Packit Service bf98b9
        case CLUTTER_PATH_MOVE_TO:
Packit Service bf98b9
          letter = 'M';
Packit Service bf98b9
          params = 1;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_REL_MOVE_TO:
Packit Service bf98b9
          letter = 'm';
Packit Service bf98b9
          params = 1;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_LINE_TO:
Packit Service bf98b9
          letter = 'L';
Packit Service bf98b9
          params = 1;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_REL_LINE_TO:
Packit Service bf98b9
          letter = 'l';
Packit Service bf98b9
          params = 1;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_CURVE_TO:
Packit Service bf98b9
          letter = 'C';
Packit Service bf98b9
          params = 3;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_REL_CURVE_TO:
Packit Service bf98b9
          letter = 'c';
Packit Service bf98b9
          params = 3;
Packit Service bf98b9
          break;
Packit Service bf98b9
Packit Service bf98b9
        case CLUTTER_PATH_CLOSE:
Packit Service bf98b9
          letter = 'z';
Packit Service bf98b9
          params = 0;
Packit Service bf98b9
          break;
Packit Service bf98b9
        }
Packit Service bf98b9
Packit Service bf98b9
      if (str->len > 0)
Packit Service bf98b9
        g_string_append_c (str, ' ');
Packit Service bf98b9
      g_string_append_c (str, letter);
Packit Service bf98b9
Packit Service bf98b9
      for (i = 0; i < params; i++)
Packit Service bf98b9
        g_string_append_printf (str, " %i %i",
Packit Service bf98b9
                                node->k.points[i].x,
Packit Service bf98b9
                                node->k.points[i].y);
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  return g_string_free (str, FALSE);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static guint
Packit Service bf98b9
clutter_path_node_distance (const ClutterKnot *start,
Packit Service bf98b9
                            const ClutterKnot *end)
Packit Service bf98b9
{
Packit Service bf98b9
  gint64 x_d, y_d;
Packit Service bf98b9
  float t;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (start != NULL, 0);
Packit Service bf98b9
  g_return_val_if_fail (end != NULL, 0);
Packit Service bf98b9
Packit Service bf98b9
  if (clutter_knot_equal (start, end))
Packit Service bf98b9
    return 0;
Packit Service bf98b9
Packit Service bf98b9
  x_d = end->x - start->x;
Packit Service bf98b9
  y_d = end->y - start->y;
Packit Service bf98b9
Packit Service bf98b9
  t = floorf (sqrtf ((x_d * x_d) + (y_d * y_d)));
Packit Service bf98b9
Packit Service bf98b9
  return (guint) t;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_ensure_node_data (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  /* Recalculate the nodes data if has changed */
Packit Service bf98b9
  if (priv->nodes_dirty)
Packit Service bf98b9
    {
Packit Service bf98b9
      GSList *l;
Packit Service bf98b9
      ClutterKnot last_position = { 0, 0 };
Packit Service bf98b9
      ClutterKnot loop_start = { 0, 0 };
Packit Service bf98b9
      ClutterKnot points[3];
Packit Service bf98b9
Packit Service bf98b9
      priv->total_length = 0;
Packit Service bf98b9
Packit Service bf98b9
      for (l = priv->nodes; l; l = l->next)
Packit Service bf98b9
        {
Packit Service bf98b9
          ClutterPathNodeFull *node = l->data;
Packit Service bf98b9
          gboolean relative = (node->k.type & CLUTTER_PATH_RELATIVE) != 0;
Packit Service bf98b9
Packit Service bf98b9
          switch (node->k.type & ~CLUTTER_PATH_RELATIVE)
Packit Service bf98b9
            {
Packit Service bf98b9
            case CLUTTER_PATH_MOVE_TO:
Packit Service bf98b9
              node->length = 0;
Packit Service bf98b9
Packit Service bf98b9
              /* Store the actual position in point[1] */
Packit Service bf98b9
              if (relative)
Packit Service bf98b9
                {
Packit Service bf98b9
                  node->k.points[1].x = last_position.x + node->k.points[0].x;
Packit Service bf98b9
                  node->k.points[1].y = last_position.y + node->k.points[0].y;
Packit Service bf98b9
                }
Packit Service bf98b9
              else
Packit Service bf98b9
                node->k.points[1] = node->k.points[0];
Packit Service bf98b9
Packit Service bf98b9
              last_position = node->k.points[1];
Packit Service bf98b9
              loop_start = node->k.points[1];
Packit Service bf98b9
              break;
Packit Service bf98b9
Packit Service bf98b9
            case CLUTTER_PATH_LINE_TO:
Packit Service bf98b9
              /* Use point[1] as the start point and point[2] as the end
Packit Service bf98b9
                 point */
Packit Service bf98b9
              node->k.points[1] = last_position;
Packit Service bf98b9
Packit Service bf98b9
              if (relative)
Packit Service bf98b9
                {
Packit Service bf98b9
                  node->k.points[2].x = (node->k.points[1].x
Packit Service bf98b9
                                         + node->k.points[0].x);
Packit Service bf98b9
                  node->k.points[2].y = (node->k.points[1].y
Packit Service bf98b9
                                         + node->k.points[0].y);
Packit Service bf98b9
                }
Packit Service bf98b9
              else
Packit Service bf98b9
                node->k.points[2] = node->k.points[0];
Packit Service bf98b9
Packit Service bf98b9
              last_position = node->k.points[2];
Packit Service bf98b9
Packit Service bf98b9
              node->length = clutter_path_node_distance (node->k.points + 1,
Packit Service bf98b9
                                                         node->k.points + 2);
Packit Service bf98b9
              break;
Packit Service bf98b9
Packit Service bf98b9
            case CLUTTER_PATH_CURVE_TO:
Packit Service bf98b9
              /* Convert to a bezier curve */
Packit Service bf98b9
              if (node->bezier == NULL)
Packit Service bf98b9
                node->bezier = _clutter_bezier_new ();
Packit Service bf98b9
Packit Service bf98b9
              if (relative)
Packit Service bf98b9
                {
Packit Service bf98b9
                  int i;
Packit Service bf98b9
Packit Service bf98b9
                  for (i = 0; i < 3; i++)
Packit Service bf98b9
                    {
Packit Service bf98b9
                      points[i].x = last_position.x + node->k.points[i].x;
Packit Service bf98b9
                      points[i].y = last_position.y + node->k.points[i].y;
Packit Service bf98b9
                    }
Packit Service bf98b9
                }
Packit Service bf98b9
              else
Packit Service bf98b9
                memcpy (points, node->k.points, sizeof (ClutterKnot) * 3);
Packit Service bf98b9
Packit Service bf98b9
              _clutter_bezier_init (node->bezier,
Packit Service bf98b9
                                    last_position.x, last_position.y,
Packit Service bf98b9
                                    points[0].x, points[0].y,
Packit Service bf98b9
                                    points[1].x, points[1].y,
Packit Service bf98b9
                                    points[2].x, points[2].y);
Packit Service bf98b9
Packit Service bf98b9
              last_position = points[2];
Packit Service bf98b9
Packit Service bf98b9
              node->length = _clutter_bezier_get_length (node->bezier);
Packit Service bf98b9
Packit Service bf98b9
              break;
Packit Service bf98b9
Packit Service bf98b9
            case CLUTTER_PATH_CLOSE:
Packit Service bf98b9
              /* Convert to a line to from last_point to loop_start */
Packit Service bf98b9
              node->k.points[1] = last_position;
Packit Service bf98b9
              node->k.points[2] = loop_start;
Packit Service bf98b9
              last_position = node->k.points[2];
Packit Service bf98b9
Packit Service bf98b9
              node->length = clutter_path_node_distance (node->k.points + 1,
Packit Service bf98b9
                                                         node->k.points + 2);
Packit Service bf98b9
              break;
Packit Service bf98b9
            }
Packit Service bf98b9
Packit Service bf98b9
          priv->total_length += node->length;
Packit Service bf98b9
        }
Packit Service bf98b9
Packit Service bf98b9
      priv->nodes_dirty = FALSE;
Packit Service bf98b9
    }
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_position:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 * @progress: a position along the path as a fraction of its length
Packit Service bf98b9
 * @position: (out): location to store the position
Packit Service bf98b9
 *
Packit Service bf98b9
 * The value in @progress represents a position along the path where
Packit Service bf98b9
 * 0.0 is the beginning and 1.0 is the end of the path. An
Packit Service bf98b9
 * interpolated position is then stored in @position.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: index of the node used to calculate the position.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
guint
Packit Service bf98b9
clutter_path_get_position (ClutterPath *path,
Packit Service bf98b9
                           gdouble progress,
Packit Service bf98b9
                           ClutterKnot *position)
Packit Service bf98b9
{
Packit Service bf98b9
  ClutterPathPrivate *priv;
Packit Service bf98b9
  GSList *l;
Packit Service bf98b9
  guint point_distance, length = 0, node_num = 0;
Packit Service bf98b9
  ClutterPathNodeFull *node;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), 0);
Packit Service bf98b9
  g_return_val_if_fail (progress >= 0.0 && progress <= 1.0, 0);
Packit Service bf98b9
Packit Service bf98b9
  priv = path->priv;
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_ensure_node_data (path);
Packit Service bf98b9
Packit Service bf98b9
  /* Special case if the path is empty, just return 0,0 for want of
Packit Service bf98b9
     something better */
Packit Service bf98b9
  if (priv->nodes == NULL)
Packit Service bf98b9
    {
Packit Service bf98b9
      memset (position, 0, sizeof (ClutterKnot));
Packit Service bf98b9
      return 0;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  /* Convert the progress to a length along the path */
Packit Service bf98b9
  point_distance = progress * priv->total_length;
Packit Service bf98b9
Packit Service bf98b9
  /* Find the node that covers this point */
Packit Service bf98b9
  for (l = priv->nodes;
Packit Service bf98b9
       l->next && point_distance >= (((ClutterPathNodeFull *) l->data)->length
Packit Service bf98b9
                                     + length);
Packit Service bf98b9
       l = l->next)
Packit Service bf98b9
    {
Packit Service bf98b9
      length += ((ClutterPathNodeFull *) l->data)->length;
Packit Service bf98b9
      node_num++;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  node = l->data;
Packit Service bf98b9
Packit Service bf98b9
  /* Convert the point distance to a distance along the node */
Packit Service bf98b9
  point_distance -= length;
Packit Service bf98b9
  if (point_distance > node->length)
Packit Service bf98b9
    point_distance = node->length;
Packit Service bf98b9
Packit Service bf98b9
  switch (node->k.type & ~CLUTTER_PATH_RELATIVE)
Packit Service bf98b9
    {
Packit Service bf98b9
    case CLUTTER_PATH_MOVE_TO:
Packit Service bf98b9
      *position = node->k.points[1];
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_LINE_TO:
Packit Service bf98b9
    case CLUTTER_PATH_CLOSE:
Packit Service bf98b9
      if (node->length == 0)
Packit Service bf98b9
        *position = node->k.points[1];
Packit Service bf98b9
      else
Packit Service bf98b9
        {
Packit Service bf98b9
          position->x = (node->k.points[1].x
Packit Service bf98b9
                         + ((node->k.points[2].x - node->k.points[1].x)
Packit Service bf98b9
                            * (gint) point_distance / (gint) node->length));
Packit Service bf98b9
          position->y = (node->k.points[1].y
Packit Service bf98b9
                         + ((node->k.points[2].y - node->k.points[1].y)
Packit Service bf98b9
                            * (gint) point_distance / (gint) node->length));
Packit Service bf98b9
        }
Packit Service bf98b9
      break;
Packit Service bf98b9
Packit Service bf98b9
    case CLUTTER_PATH_CURVE_TO:
Packit Service bf98b9
      if (node->length == 0)
Packit Service bf98b9
        *position = node->k.points[2];
Packit Service bf98b9
      else
Packit Service bf98b9
        {
Packit Service bf98b9
          _clutter_bezier_advance (node->bezier,
Packit Service bf98b9
                                   point_distance * CLUTTER_BEZIER_MAX_LENGTH
Packit Service bf98b9
                                   / node->length,
Packit Service bf98b9
                                   position);
Packit Service bf98b9
        }
Packit Service bf98b9
      break;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  return node_num;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_get_length:
Packit Service bf98b9
 * @path: a #ClutterPath
Packit Service bf98b9
 *
Packit Service bf98b9
 * Retrieves an approximation of the total length of the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the length of the path.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
guint
Packit Service bf98b9
clutter_path_get_length (ClutterPath *path)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_val_if_fail (CLUTTER_IS_PATH (path), 0);
Packit Service bf98b9
Packit Service bf98b9
  clutter_path_ensure_node_data (path);
Packit Service bf98b9
Packit Service bf98b9
  return path->priv->total_length;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static ClutterPathNodeFull *
Packit Service bf98b9
clutter_path_node_full_new (void)
Packit Service bf98b9
{
Packit Service bf98b9
  return g_slice_new0 (ClutterPathNodeFull);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
static void
Packit Service bf98b9
clutter_path_node_full_free (ClutterPathNodeFull *node)
Packit Service bf98b9
{
Packit Service bf98b9
  if (node->bezier)
Packit Service bf98b9
    _clutter_bezier_free (node->bezier);
Packit Service bf98b9
Packit Service bf98b9
  g_slice_free (ClutterPathNodeFull, node);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_node_copy:
Packit Service bf98b9
 * @node: a #ClutterPathNode
Packit Service bf98b9
 *
Packit Service bf98b9
 * Makes an allocated copy of a node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the copied node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
ClutterPathNode *
Packit Service bf98b9
clutter_path_node_copy (const ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  return g_slice_dup (ClutterPathNode, node);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_node_free:
Packit Service bf98b9
 * @node: a #ClutterPathNode
Packit Service bf98b9
 *
Packit Service bf98b9
 * Frees the memory of an allocated node.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_path_node_free (ClutterPathNode *node)
Packit Service bf98b9
{
Packit Service bf98b9
  if (G_LIKELY (node))
Packit Service bf98b9
    g_slice_free (ClutterPathNode, node);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_path_node_equal:
Packit Service bf98b9
 * @node_a: First node
Packit Service bf98b9
 * @node_b: Second node
Packit Service bf98b9
 *
Packit Service bf98b9
 * Compares two nodes and checks if they are the same type with the
Packit Service bf98b9
 * same coordinates.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: %TRUE if the nodes are the same.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 1.0
Packit Service bf98b9
 */
Packit Service bf98b9
gboolean
Packit Service bf98b9
clutter_path_node_equal (const ClutterPathNode *node_a,
Packit Service bf98b9
                         const ClutterPathNode *node_b)
Packit Service bf98b9
{
Packit Service bf98b9
  guint n_points, i;
Packit Service bf98b9
Packit Service bf98b9
  g_return_val_if_fail (node_a != NULL, FALSE);
Packit Service bf98b9
  g_return_val_if_fail (node_b != NULL, FALSE);
Packit Service bf98b9
Packit Service bf98b9
  if (node_a->type != node_b->type)
Packit Service bf98b9
    return FALSE;
Packit Service bf98b9
Packit Service bf98b9
  switch (node_a->type & ~CLUTTER_PATH_RELATIVE)
Packit Service bf98b9
    {
Packit Service bf98b9
    case CLUTTER_PATH_MOVE_TO: n_points = 1; break;
Packit Service bf98b9
    case CLUTTER_PATH_LINE_TO: n_points = 1; break;
Packit Service bf98b9
    case CLUTTER_PATH_CURVE_TO: n_points = 3; break;
Packit Service bf98b9
    case CLUTTER_PATH_CLOSE: n_points = 0; break;
Packit Service bf98b9
    default: return FALSE;
Packit Service bf98b9
    }
Packit Service bf98b9
Packit Service bf98b9
  for (i = 0; i < n_points; i++)
Packit Service bf98b9
    if (node_a->points[i].x != node_b->points[i].x
Packit Service bf98b9
        || node_a->points[i].y != node_b->points[i].y)
Packit Service bf98b9
      return FALSE;
Packit Service bf98b9
Packit Service bf98b9
  return TRUE;
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
G_DEFINE_BOXED_TYPE (ClutterKnot, clutter_knot,
Packit Service bf98b9
                     clutter_knot_copy,
Packit Service bf98b9
                     clutter_knot_free);
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_knot_copy:
Packit Service bf98b9
 * @knot: a #ClutterKnot
Packit Service bf98b9
 *
Packit Service bf98b9
 * Makes an allocated copy of a knot.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: the copied knot.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 0.2
Packit Service bf98b9
 */
Packit Service bf98b9
ClutterKnot *
Packit Service bf98b9
clutter_knot_copy (const ClutterKnot *knot)
Packit Service bf98b9
{
Packit Service bf98b9
  if (G_UNLIKELY (knot == NULL))
Packit Service bf98b9
    return NULL;
Packit Service bf98b9
Packit Service bf98b9
  return g_slice_dup (ClutterKnot, knot);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_knot_free:
Packit Service bf98b9
 * @knot: a #ClutterKnot
Packit Service bf98b9
 *
Packit Service bf98b9
 * Frees the memory of an allocated knot.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 0.2
Packit Service bf98b9
 */
Packit Service bf98b9
void
Packit Service bf98b9
clutter_knot_free (ClutterKnot *knot)
Packit Service bf98b9
{
Packit Service bf98b9
  if (G_LIKELY (knot != NULL))
Packit Service bf98b9
    g_slice_free (ClutterKnot, knot);
Packit Service bf98b9
}
Packit Service bf98b9
Packit Service bf98b9
/**
Packit Service bf98b9
 * clutter_knot_equal:
Packit Service bf98b9
 * @knot_a: First knot
Packit Service bf98b9
 * @knot_b: Second knot
Packit Service bf98b9
 *
Packit Service bf98b9
 * Compares to knot and checks if the point to the same location.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Return value: %TRUE if the knots point to the same location.
Packit Service bf98b9
 *
Packit Service bf98b9
 * Since: 0.2
Packit Service bf98b9
 */
Packit Service bf98b9
gboolean
Packit Service bf98b9
clutter_knot_equal (const ClutterKnot *knot_a,
Packit Service bf98b9
                    const ClutterKnot *knot_b)
Packit Service bf98b9
{
Packit Service bf98b9
  g_return_val_if_fail (knot_a != NULL, FALSE);
Packit Service bf98b9
  g_return_val_if_fail (knot_b != NULL, FALSE);
Packit Service bf98b9
Packit Service bf98b9
  if (knot_a == knot_b)
Packit Service bf98b9
    return TRUE;
Packit Service bf98b9
Packit Service bf98b9
  return knot_a->x == knot_b->x && knot_a->y == knot_b->y;
Packit Service bf98b9
}