[clutter/wip/actor-content: 21/23] Add BorderImage



commit e5cf5927495b690e744af5992fb52fbd46ba0965
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Wed Dec 8 12:56:00 2010 +0000

    Add BorderImage
    
    ClutterBorderImage is a simple class implementing part of the semantics
    of the border-image CSS3 pragma. It allows painting a content as a
    background or a border, repeating a pattern to fill the paint area.

 clutter/Makefile.am                        |    2 +
 clutter/clutter-border-image.c             |  468 ++++++++++++++++++++++++++++
 clutter/clutter-border-image.h             |  103 ++++++
 clutter/clutter.h                          |    1 +
 doc/reference/clutter/clutter-docs.xml.in  |    3 +-
 doc/reference/clutter/clutter-sections.txt |   19 ++
 doc/reference/clutter/clutter.types        |    1 +
 tests/data/Makefile.am                     |    1 +
 tests/data/border-image.png                |  Bin 0 -> 1355 bytes
 tests/interactive/Makefile.am              |    3 +-
 tests/interactive/test-border-image.c      |  105 +++++++
 11 files changed, 704 insertions(+), 2 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 6cfafab..024b018 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -90,6 +90,7 @@ source_h =					\
 	$(srcdir)/clutter-binding-pool.h 	\
 	$(srcdir)/clutter-bin-layout.h		\
 	$(srcdir)/clutter-blur-effect.h		\
+	$(srcdir)/clutter-border-image.h	\
 	$(srcdir)/clutter-box.h			\
 	$(srcdir)/clutter-box-layout.h		\
 	$(srcdir)/clutter-cairo-texture.h	\
@@ -178,6 +179,7 @@ source_c = \
 	$(srcdir)/clutter-binding-pool.c	\
 	$(srcdir)/clutter-bin-layout.c		\
 	$(srcdir)/clutter-blur-effect.c		\
+	$(srcdir)/clutter-border-image.c	\
 	$(srcdir)/clutter-box.c			\
 	$(srcdir)/clutter-box-layout.c		\
 	$(srcdir)/clutter-cairo-texture.c       \
diff --git a/clutter/clutter-border-image.c b/clutter/clutter-border-image.c
new file mode 100644
index 0000000..4ce1d23
--- /dev/null
+++ b/clutter/clutter-border-image.c
@@ -0,0 +1,468 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010  Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:clutter-border-image
+ * @Title: ClutterBorderImage
+ * @Short_Description: A border image content
+ *
+ * #ClutterBorderImage is a #ClutterImage sub-class that is suitable for
+ * displaying backgrounds and borders that fit a given area.
+ *
+ * #ClutterBorderImage paints the image data using nine slices, defined
+ * by the area it has to fit and by four inward offsets from the edges
+ * of the image, expressed in floating point values between 0.0 and 1.0.
+ *
+ * #ClutterBorderImage is available since Clutter 1.6
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "clutter-border-image.h"
+
+#include "clutter-content.h"
+#include "clutter-private.h"
+
+enum
+{
+  TOP,
+  RIGHT,
+  BOTTOM,
+  LEFT,
+
+  N_SLICES
+};
+
+struct _ClutterBorderImagePrivate
+{
+  gdouble slices[N_SLICES];
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_SLICE_TOP,
+  PROP_SLICE_RIGHT,
+  PROP_SLICE_BOTTOM,
+  PROP_SLICE_LEFT,
+
+  LAST_PROP
+};
+
+static GParamSpec *border_props[LAST_PROP] = { NULL, };
+
+static CoglMaterial *border_template_material = NULL;
+
+static void clutter_content_iface_init (ClutterContentIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterBorderImage,
+                         clutter_border_image,
+                         CLUTTER_TYPE_IMAGE,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
+                                                clutter_content_iface_init));
+
+static void
+clutter_border_image_update_geometry (ClutterContent *content,
+                                      ClutterActor   *actor)
+{
+  ClutterBorderImagePrivate *priv = CLUTTER_BORDER_IMAGE (content)->priv;
+  ClutterImage *image = CLUTTER_IMAGE (content);
+  ClutterActorBox allocation;
+  gfloat width, height;
+  gint image_width, image_height;
+  float tx1, ty1, tx2, ty2;
+  float ex, ey;
+  float top, bottom, right, left;
+
+  clutter_image_get_size (image, &image_width, &image_height);
+  if (image_width == 0 && image_height == 0)
+    return;
+
+  clutter_actor_get_allocation_box (actor, &allocation);
+  clutter_actor_box_get_size (&allocation, &width, &height);
+
+  /* round to pixel-aligned positions */
+  top = ceilf (image_height * priv->slices[TOP]);
+  bottom = floorf (image_height * (1.0 - priv->slices[BOTTOM]));
+  left = ceilf (image_width * priv->slices[LEFT]);
+  right = floorf (image_width * (1.0 - priv->slices[RIGHT]));
+
+  tx1 = priv->slices[LEFT];
+  tx2 = 1.0 - priv->slices[RIGHT];
+  ty1 = priv->slices[TOP];
+  ty2 = 1.0 - priv->slices[BOTTOM];
+
+  ex = width - (image_width - right);
+  if (ex < left)
+    ex = left;
+
+  ey = height - (image_height - bottom);
+  if (ey < left)
+    ey = left;
+
+  {
+    GLfloat rectangles[] = {
+      /* top left corner */
+      0, 0, left, top,
+      0.0, 0.0,
+      tx1, ty1,
+
+      /* top middle */
+      left, 0, ex, top,
+      tx1, 0.0,
+      tx2, ty1,
+
+      /* top right */
+      ex, 0, width, top,
+      tx2, 0.0,
+      1.0, ty1,
+
+      /* mid left */
+      0, top, left, ey,
+      0.0, ty1,
+      tx1, ty2,
+
+      /* center */
+      left, top, ex, ey,
+      tx1, ty1,
+      tx2, ty2,
+
+      /* mid right */
+      ex, top, width, ey,
+      tx2, ty1,
+      1.0, ty2,
+
+      /* bottom left */
+      0, ey, left, height,
+      0.0, ty2,
+      tx1, 1.0,
+
+      /* bottom center */
+      left, ey, ex, height,
+      tx1, ty2,
+      tx2, 1.0,
+
+      /* bottom right */
+      ex, ey, width, height,
+      tx2, ty2,
+      1.0, 1.0
+    };
+
+    cogl_rectangles_with_texture_coords (rectangles, 9);
+  }
+}
+
+static void
+clutter_content_iface_init (ClutterContentIface *iface)
+{
+  iface->update_geometry = clutter_border_image_update_geometry;
+}
+
+static CoglMaterial *
+clutter_border_image_create_material (ClutterImage *image)
+{
+  if (border_template_material == NULL)
+    {
+      CoglHandle dummy;
+
+      dummy = cogl_texture_new_with_size (1, 1,
+                                          COGL_TEXTURE_NO_SLICING,
+                                          COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+
+      border_template_material = cogl_material_new ();
+      cogl_material_set_layer (border_template_material, 0, dummy);
+      cogl_material_set_layer_filters (border_template_material, 0,
+                                       COGL_MATERIAL_FILTER_NEAREST,
+                                       COGL_MATERIAL_FILTER_NEAREST);
+      cogl_handle_unref (dummy);
+    }
+
+  return cogl_material_copy (border_template_material);
+}
+
+static inline void
+clutter_border_image_set_slice_internal (ClutterBorderImage *image,
+                                         int                 position,
+                                         gdouble             new_value,
+                                         GParamSpec         *pspec)
+{
+  ClutterBorderImagePrivate *priv = image->priv;
+
+  g_assert (position >= TOP && position < N_SLICES);
+
+  if (priv->slices[position] != new_value)
+    {
+      priv->slices[position] = new_value;
+      g_object_notify_by_pspec (G_OBJECT (image), pspec);
+    }
+}
+
+static void
+clutter_border_image_set_property (GObject      *gobject,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterBorderImage *image = CLUTTER_BORDER_IMAGE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_SLICE_TOP:
+      clutter_border_image_set_slice_internal (image, TOP,
+                                               g_value_get_double (value),
+                                               pspec);
+      break;
+
+    case PROP_SLICE_RIGHT:
+      clutter_border_image_set_slice_internal (image, RIGHT,
+                                               g_value_get_double (value),
+                                               pspec);
+      break;
+
+    case PROP_SLICE_BOTTOM:
+      clutter_border_image_set_slice_internal (image, BOTTOM,
+                                               g_value_get_double (value),
+                                               pspec);
+      break;
+
+    case PROP_SLICE_LEFT:
+      clutter_border_image_set_slice_internal (image, LEFT,
+                                               g_value_get_double (value),
+                                               pspec);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+clutter_border_image_get_property (GObject    *gobject,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{  ClutterBorderImagePrivate *priv = CLUTTER_BORDER_IMAGE (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_SLICE_TOP:
+      g_value_set_double (value, priv->slices[TOP]);
+      break;
+
+    case PROP_SLICE_RIGHT:
+      g_value_set_double (value, priv->slices[RIGHT]);
+      break;
+
+    case PROP_SLICE_BOTTOM:
+      g_value_set_double (value, priv->slices[BOTTOM]);
+      break;
+
+    case PROP_SLICE_LEFT:
+      g_value_set_double (value, priv->slices[LEFT]);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+clutter_border_image_class_init (ClutterBorderImageClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterImageClass *image_class = CLUTTER_IMAGE_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ClutterBorderImagePrivate));
+
+  /**
+   * ClutterBorderImage:slice-top:
+   *
+   * The inward offset of the vertical slices from the top edge.
+   *
+   * Since: 1.6
+   */
+  border_props[PROP_SLICE_TOP] =
+    g_param_spec_double ("slice-top",
+                         P_("Slice Top"),
+                         P_("The relative size of the top slice"),
+                         0.0, 1.0,
+                         0.0,
+                         CLUTTER_PARAM_READWRITE);
+
+  /**
+   * ClutterBorderImage:slice-right:
+   *
+   * The inward offset of the horizontal slices from the right edge.
+   *
+   * Since: 1.6
+   */
+  border_props[PROP_SLICE_RIGHT] =
+    g_param_spec_double ("slice-right",
+                         P_("Slice Right"),
+                         P_("The relative size of the right slice"),
+                         0.0, 1.0,
+                         0.0,
+                         CLUTTER_PARAM_READWRITE);
+
+  /**
+   * ClutterBorderImage:slice-bottom:
+   *
+   * The inward offset of the vertical slices from the bottom edge.
+   *
+   * Since: 1.6
+   */
+  border_props[PROP_SLICE_BOTTOM] =
+    g_param_spec_double ("slice-bottom",
+                         P_("Slice Bottom"),
+                         P_("The relative size of the bottom slice"),
+                         0.0, 1.0,
+                         0.0,
+                         CLUTTER_PARAM_READWRITE);
+
+  /**
+   * ClutterBorderImage:slice-left:
+   *
+   * The inward offset of the horizontal slices from the left edge.
+   *
+   * Since: 1.6
+   */
+  border_props[PROP_SLICE_LEFT] =
+    g_param_spec_double ("slice-left",
+                         P_("Slice Left"),
+                         P_("The relative size of the left slice"),
+                         0.0, 1.0,
+                         0.0,
+                         CLUTTER_PARAM_READWRITE);
+
+  gobject_class->set_property = clutter_border_image_set_property;
+  gobject_class->get_property = clutter_border_image_get_property;
+  g_object_class_install_properties (gobject_class,
+                                     LAST_PROP,
+                                     border_props);
+
+  image_class->create_material = clutter_border_image_create_material;
+}
+
+static void
+clutter_border_image_init (ClutterBorderImage *image)
+{
+  image->priv = G_TYPE_INSTANCE_GET_PRIVATE (image, CLUTTER_TYPE_BORDER_IMAGE,
+                                             ClutterBorderImagePrivate);
+
+  memset (image->priv->slices, 0, sizeof (gdouble) * N_SLICES);
+}
+
+/**
+ * clutter_border_image_new:
+ *
+ * Creates a new #ClutterBorderImage
+ *
+ * Return value: (transfer full): the newly created #ClutterBorderImage
+ *
+ * Since: 1.6
+ */
+ClutterContent *
+clutter_border_image_new (void)
+{
+  return g_object_new (CLUTTER_TYPE_BORDER_IMAGE, NULL);
+}
+
+/**
+ * clutter_border_image_set_slices:
+ * @image: a #ClutterBorderImage
+ * @top: the offset from the top, between 0.0 and 1.0
+ * @right: the offset from the right, between 0.0 and 1.0
+ * @bottom: the offset from the bottom, between 0.0 and 1.0
+ * @left: the offset from the left, between 0.0 and 1.0
+ *
+ * Sets the inward offsets of @image. The offsets are relative
+ * to the current size of the image data.
+ *
+ * Since: 1.6
+ */
+void
+clutter_border_image_set_slices (ClutterBorderImage *image,
+                                 gdouble             top,
+                                 gdouble             right,
+                                 gdouble             bottom,
+                                 gdouble             left)
+{
+  g_return_if_fail (CLUTTER_IS_BORDER_IMAGE (image));
+
+  g_object_freeze_notify (G_OBJECT (image));
+
+  clutter_border_image_set_slice_internal (image, TOP,
+                                           top,
+                                           border_props[PROP_SLICE_TOP]);
+  clutter_border_image_set_slice_internal (image, RIGHT,
+                                           right,
+                                           border_props[PROP_SLICE_RIGHT]);
+  clutter_border_image_set_slice_internal (image, BOTTOM,
+                                           bottom,
+                                           border_props[PROP_SLICE_BOTTOM]);
+  clutter_border_image_set_slice_internal (image, LEFT,
+                                           left,
+                                           border_props[PROP_SLICE_LEFT]);
+
+  clutter_content_invalidate (CLUTTER_CONTENT (image));
+
+  g_object_thaw_notify (G_OBJECT (image));
+}
+
+/**
+ * clutter_border_image_get_slices:
+ * @image: a #ClutterBorderImage
+ * @top: (out): return location for the offset from the top, or %NULL
+ * @right: (out): return location for the offset from the right, or %NULL
+ * @bottom: (out): return location for the offset from the bottom, or %NULL
+ * @left: (out): return location for the offset from the left, or %NULL
+ *
+ * Retrieves the offsets set using clutter_border_image_set_slices().
+ *
+ * Since: 1.6
+ */
+void
+clutter_border_image_get_slices (ClutterBorderImage *image,
+                                 gdouble            *top,
+                                 gdouble            *right,
+                                 gdouble            *bottom,
+                                 gdouble            *left)
+{
+  g_return_if_fail (CLUTTER_IS_BORDER_IMAGE (image));
+
+  if (top)
+    *top = image->priv->slices[TOP];
+
+  if (right)
+    *right = image->priv->slices[RIGHT];
+
+  if (bottom)
+    *bottom = image->priv->slices[BOTTOM];
+
+  if (left)
+    *left = image->priv->slices[LEFT];
+}
diff --git a/clutter/clutter-border-image.h b/clutter/clutter-border-image.h
new file mode 100644
index 0000000..12c6ffa
--- /dev/null
+++ b/clutter/clutter-border-image.h
@@ -0,0 +1,103 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010  Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_BORDER_IMAGE_H__
+#define __CLUTTER_BORDER_IMAGE_H__
+
+#include <clutter/clutter-image.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BORDER_IMAGE               (clutter_border_image_get_type ())
+#define CLUTTER_BORDER_IMAGE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BORDER_IMAGE, ClutterBorderImage))
+#define CLUTTER_IS_BORDER_IMAGE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BORDER_IMAGE))
+#define CLUTTER_BORDER_IMAGE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BORDER_IMAGE, ClutterBorderImageClass))
+#define CLUTTER_IS_BORDER_IMAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BORDER_IMAGE))
+#define CLUTTER_BORDER_IMAGE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BORDER_IMAGE, ClutterBorderImageClass))
+
+typedef struct _ClutterBorderImage              ClutterBorderImage;
+typedef struct _ClutterBorderImagePrivate       ClutterBorderImagePrivate;
+typedef struct _ClutterBorderImageClass         ClutterBorderImageClass;
+
+/**
+ * ClutterBorderImage:
+ *
+ * The <structname>ClutterBorderImage</structname> structure contains
+ * private data and should only be accessed using the provided API.
+ *
+ * Since: 1.6
+ */
+struct _ClutterBorderImage
+{
+  /*< private >*/
+  ClutterImage parent_instance;
+
+  ClutterBorderImagePrivate *priv;
+};
+
+/**
+ * ClutterBorderImage:
+ *
+ * The <structname>ClutterBorderImageClass</structname> structure contains
+ * only private data.
+ *
+ * Since: 1.6
+ */
+struct _ClutterBorderImageClass
+{
+  /*< private >*/
+  ClutterImageClass parent_class;
+
+  void (* _clutter_border_image_0) (void);
+  void (* _clutter_border_image_1) (void);
+  void (* _clutter_border_image_2) (void);
+  void (* _clutter_border_image_3) (void);
+  void (* _clutter_border_image_4) (void);
+  void (* _clutter_border_image_5) (void);
+  void (* _clutter_border_image_6) (void);
+  void (* _clutter_border_image_7) (void);
+};
+
+GType clutter_border_image_get_type (void) G_GNUC_CONST;
+
+ClutterContent *        clutter_border_image_new                (void);
+
+void                    clutter_border_image_set_slices         (ClutterBorderImage      *image,
+                                                                 gdouble                  top,
+                                                                 gdouble                  right,
+                                                                 gdouble                  bottom,
+                                                                 gdouble                  left);
+void                    clutter_border_image_get_slices         (ClutterBorderImage      *image,
+                                                                 gdouble                 *top,
+                                                                 gdouble                 *right,
+                                                                 gdouble                 *bottom,
+                                                                 gdouble                 *left);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BORDER_IMAGE_H__ */
diff --git a/clutter/clutter.h b/clutter/clutter.h
index a700fae..5029be4 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -52,6 +52,7 @@
 #include "clutter-binding-pool.h"
 #include "clutter-bin-layout.h"
 #include "clutter-blur-effect.h"
+#include "clutter-border-image.h"
 #include "clutter-box.h"
 #include "clutter-box-layout.h"
 #include "clutter-cairo-texture.h"
diff --git a/doc/reference/clutter/clutter-docs.xml.in b/doc/reference/clutter/clutter-docs.xml.in
index 81eaef4..3c7de11 100644
--- a/doc/reference/clutter/clutter-docs.xml.in
+++ b/doc/reference/clutter/clutter-docs.xml.in
@@ -126,8 +126,9 @@
     <chapter>
       <title>Content</title>
 
-      <xi:include href="xml/clutter-image.xml"/>
       <xi:include href="xml/clutter-rgba.xml"/>
+      <xi:include href="xml/clutter-image.xml"/>
+      <xi:include href="xml/clutter-border-image.xml"/>
     </chapter>
 
   </part>
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 395cd55..461741a 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -2749,3 +2749,22 @@ CLUTTER_IS_IMAGE_LOADER_CLASS
 <SUBSECTION Private>
 clutter_image_loader_get_type
 </SECTION>
+
+<SECTION>
+<FILE>clutter-border-image</FILE>
+ClutterBorderImage
+ClutterBorderImageClass
+clutter_border_image_new
+clutter_border_image_set_slices
+clutter_border_image_get_slices
+<SUBSECTION Standard>
+CLUTTER_TYPE_BORDER_IMAGE
+CLUTTER_BORDER_IMAGE
+CLUTTER_BORDER_IMAGE_CLASS
+CLUTTER_BORDER_IMAGE_GET_CLASS
+CLUTTER_IS_BORDER_IMAGE
+CLUTTER_IS_BORDER_IMAGE_CLASS
+<SUBSECTION Private>
+ClutterBorderImagePrivate
+clutter_border_image_get_type
+</SECTION>
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types
index d35435a..7534628 100644
--- a/doc/reference/clutter/clutter.types
+++ b/doc/reference/clutter/clutter.types
@@ -19,6 +19,7 @@ clutter_bind_constraint_get_type
 clutter_binding_pool_get_type
 clutter_bin_layout_get_type
 clutter_blur_effect_get_type
+clutter_border_image_get_type
 clutter_box_get_type
 clutter_box_layout_get_type
 clutter_cairo_texture_get_type
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index f886a6d..e94cb21 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -20,6 +20,7 @@ png_files = \
 	redhand.png 		\
 	redhand_alpha.png	\
 	light0.png 		\
+	border-image.png	\
 	$(NULL)
 
 EXTRA_DIST = $(json_files) $(png_files) clutter-1.0.suppressions
diff --git a/tests/data/border-image.png b/tests/data/border-image.png
new file mode 100644
index 0000000..c74ddc0
Binary files /dev/null and b/tests/data/border-image.png differ
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index 666eaeb..b7d7598 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -57,7 +57,8 @@ UNIT_TESTS = \
 	test-path-constraint.c \
 	test-snap-constraint.c \
 	test-rgba-content.c \
-	test-image-content.c
+	test-image-content.c \
+	test-border-image.c
 
 if X11_TESTS
 UNIT_TESTS += test-pixmap.c test-devices.c
diff --git a/tests/interactive/test-border-image.c b/tests/interactive/test-border-image.c
new file mode 100644
index 0000000..4b0cac7
--- /dev/null
+++ b/tests/interactive/test-border-image.c
@@ -0,0 +1,105 @@
+#include <stdlib.h>
+#include <gmodule.h>
+#include <gio/gio.h>
+#include <clutter/clutter.h>
+
+#define STAGE_WIDTH     400
+#define STAGE_HEIGHT    400
+#define PADDING         10
+#define SPACING         2
+#define RECT_SIZE       64
+
+static void
+load_async_done (GObject      *gobject,
+                 GAsyncResult *result,
+                 gpointer      dummy G_GNUC_UNUSED)
+{
+  GError *error = NULL;
+  gboolean res;
+  int width, height;
+
+  res = clutter_image_load_finish (CLUTTER_IMAGE (gobject), result,
+                                   &width,
+                                   &height,
+                                   &error);
+  if (!res)
+    {
+      g_print ("Unable to load 'border-image.png': %s", error->message);
+      g_error_free (error);
+      return;
+    }
+}
+
+G_MODULE_EXPORT int
+test_border_image_main (int   argc,
+                        char *argv[])
+{
+  ClutterActor *stage, *group;
+  ClutterContent *content;
+  int i, j, n_cols, n_rows;
+  float last_x, last_y;
+  GFile *gfile;
+
+  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  stage = clutter_stage_new ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "Border Image");
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+  clutter_actor_set_size (stage, 400, 400);
+  clutter_actor_show (stage);
+
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  content = clutter_border_image_new ();
+  clutter_border_image_set_slices (CLUTTER_BORDER_IMAGE (content),
+                                   0.26, 0.413, 0.26, 0.413);
+  gfile = g_file_new_for_path (TESTS_DATADIR "/border-image.png");
+  clutter_image_load_async (CLUTTER_IMAGE (content), gfile, NULL,
+                            load_async_done,
+                            NULL);
+  g_object_unref (gfile);
+
+  group = clutter_group_new ();
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+  clutter_actor_add_constraint (group, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
+  clutter_actor_add_constraint (group, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
+  clutter_actor_set_content (group, content);
+  g_object_unref (content);
+
+  content = clutter_rgba_new (g_random_double_range (0.0, 1.0),
+                              g_random_double_range (0.0, 1.0),
+                              g_random_double_range (0.0, 1.0),
+                              0.25);
+
+  n_cols = (STAGE_WIDTH  - (2 * PADDING)) / (RECT_SIZE + (2 * SPACING));
+  n_rows = (STAGE_HEIGHT - (2 * PADDING)) / (RECT_SIZE + (2 * SPACING));
+
+  last_y = PADDING + SPACING;
+  for (i = 0; i < n_rows; i++)
+    {
+      last_x = PADDING + SPACING;
+      for (j = 0; j < n_cols; j++)
+        {
+          ClutterActor *rect = clutter_actor_new ();
+
+          clutter_actor_set_position (rect, last_x, last_y);
+          clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE);
+          clutter_actor_set_content (rect, content);
+
+          clutter_container_add_actor (CLUTTER_CONTAINER (group), rect);
+
+          last_x += RECT_SIZE + SPACING;
+        }
+
+      last_y += RECT_SIZE + SPACING;
+    }
+
+  clutter_actor_set_size (group, last_x + PADDING, last_y + PADDING);
+
+  g_object_unref (content);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]