[gtk/wip/otte/canvas: 25/36] canvas: Redo points and sizes




commit 9eedd3f5acd09bece2c1436b1c061277c53b5ba5
Author: Benjamin Otte <otte redhat com>
Date:   Sat Jul 2 19:24:43 2022 +0200

    canvas: Redo points and sizes
    
    Instead of lots of special cases, just have 3 types:
    * sums
    * constants
    * variables
    
    And implement it in a new GtkCanvasVec2 struct and use it for points and
    sizes.
    
    Simplifies te code a lot.
    
    Requires some changes though so that now all variables are
    preinitialized instead of queried on demand.

 demos/gtk-demo/canvas_intro.c  |   2 +-
 demos/gtk-demo/canvas_puzzle.c |   2 +-
 gtk/gtkcanvas.c                |  30 ++-
 gtk/gtkcanvasbox.c             |  91 +++++----
 gtk/gtkcanvasboxprivate.h      |  17 +-
 gtk/gtkcanvasitem.c            |  78 +++++++-
 gtk/gtkcanvasitemprivate.h     |   7 +
 gtk/gtkcanvaspoint.c           | 227 ++++------------------
 gtk/gtkcanvaspoint.h           |   4 +-
 gtk/gtkcanvaspointprivate.h    |  52 -----
 gtk/gtkcanvassize.c            | 432 +++++------------------------------------
 gtk/gtkcanvassizeprivate.h     |  84 --------
 gtk/gtkcanvasvec2.c            | 343 ++++++++++++++++++++++++++++++++
 gtk/gtkcanvasvec2private.h     |  99 ++++++++++
 gtk/meson.build                |   1 +
 15 files changed, 695 insertions(+), 774 deletions(-)
---
diff --git a/demos/gtk-demo/canvas_intro.c b/demos/gtk-demo/canvas_intro.c
index 7216b7a7e7..715bb2529f 100644
--- a/demos/gtk-demo/canvas_intro.c
+++ b/demos/gtk-demo/canvas_intro.c
@@ -27,7 +27,7 @@ bind_item (GtkListItemFactory *factory,
                             0.0, 0.0);
   gtk_canvas_point_free (point);
 
-  point = gtk_canvas_point_new_from_box (box, 0.5, 0.5, 0, 0);
+  point = gtk_canvas_point_new_from_box (box, 0.5, 0.5);
   gtk_canvas_box_free (box);
   size = gtk_canvas_size_new_measure_item (ci, GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN);
   box = gtk_canvas_box_new (point, size, 0.5, 0.5);
diff --git a/demos/gtk-demo/canvas_puzzle.c b/demos/gtk-demo/canvas_puzzle.c
index 07b0d5f66d..c30d24a346 100644
--- a/demos/gtk-demo/canvas_puzzle.c
+++ b/demos/gtk-demo/canvas_puzzle.c
@@ -27,7 +27,7 @@ set_item_position (GtkCanvasItem *ci,
                                  0.0, 0.0);
   gtk_canvas_point_free (point);
 
-  point = gtk_canvas_point_new_from_box (viewport, x, y, 0, 0);
+  point = gtk_canvas_point_new_from_box (viewport, x, y);
   gtk_canvas_box_free (viewport);
   size = gtk_canvas_size_new (0, 0);
   box = gtk_canvas_box_new (point, size, x, y);
diff --git a/gtk/gtkcanvas.c b/gtk/gtkcanvas.c
index e7047be63f..a1aef6f566 100644
--- a/gtk/gtkcanvas.c
+++ b/gtk/gtkcanvas.c
@@ -23,7 +23,8 @@
 
 #include "gtkcanvasbox.h"
 #include "gtkcanvasitemprivate.h"
-#include "gtkcanvassizeprivate.h"
+#include "gtkcanvassize.h"
+#include "gtkcanvasvec2private.h"
 #include "gtkintl.h"
 #include "gtklistitemfactory.h"
 #include "gtkwidgetprivate.h"
@@ -53,7 +54,7 @@ struct _GtkCanvas
   GtkCanvasItems items;
   GHashTable *item_lookup;
 
-  GtkCanvasSize viewport_size;
+  GtkCanvasVec2 viewport_size;
 };
 
 enum
@@ -164,7 +165,7 @@ gtk_canvas_finalize (GObject *object)
   GtkCanvas *self = GTK_CANVAS (object);
 
   g_hash_table_unref (self->item_lookup);
-  gtk_canvas_size_finish (&self->viewport_size);
+  gtk_canvas_vec2_finish (&self->viewport_size);
 
   G_OBJECT_CLASS (gtk_canvas_parent_class)->finalize (object);
 }
@@ -217,6 +218,19 @@ gtk_canvas_set_property (GObject      *object,
     }
 }
 
+static void
+gtk_canvas_validate_variables (GtkCanvas *self)
+{
+  int i;
+
+  for (i = 0; i < gtk_canvas_items_get_size (&self->items); i++)
+    {
+      GtkCanvasItem *ci = gtk_canvas_items_get (&self->items, i);
+
+      gtk_canvas_item_validate_variables (ci);
+    }
+}
+
 static void
 gtk_canvas_allocate (GtkWidget *widget,
                      int        width,
@@ -226,8 +240,9 @@ gtk_canvas_allocate (GtkWidget *widget,
   GtkCanvas *self = GTK_CANVAS (widget);
   gsize i;
 
-  self->viewport_size.reference.reference->width = width;
-  self->viewport_size.reference.reference->height = height;
+  gtk_canvas_validate_variables (self);
+
+  gtk_canvas_vec2_init_constant (gtk_canvas_vec2_get_variable (&self->viewport_size), width, height);
 
   for (i = 0; i < gtk_canvas_items_get_size (&self->items); i++)
     {
@@ -317,8 +332,7 @@ gtk_canvas_init (GtkCanvas *self)
 {
   self->item_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-  gtk_canvas_size_init_reference (&self->viewport_size,
-                                  g_rc_box_new0 (graphene_size_t));
+  gtk_canvas_vec2_init_variable (&self->viewport_size);
 }
 
 /**
@@ -494,5 +508,5 @@ gtk_canvas_lookup_item (GtkCanvas *self,
 const GtkCanvasSize *
 gtk_canvas_get_viewport_size (GtkCanvas *self)
 {
-  return &self->viewport_size;
+  return (const GtkCanvasSize *) &self->viewport_size;
 }
diff --git a/gtk/gtkcanvasbox.c b/gtk/gtkcanvasbox.c
index 48b31fdc92..52dac1f7cc 100644
--- a/gtk/gtkcanvasbox.c
+++ b/gtk/gtkcanvasbox.c
@@ -31,9 +31,6 @@
 
 #include "gtkcanvasboxprivate.h"
 
-#include "gtkcanvaspointprivate.h"
-#include "gtkcanvassizeprivate.h"
-
 /* {{{ Boilerplate */
 
 G_DEFINE_BOXED_TYPE (GtkCanvasBox, gtk_canvas_box,
@@ -41,33 +38,28 @@ G_DEFINE_BOXED_TYPE (GtkCanvasBox, gtk_canvas_box,
                      gtk_canvas_box_free)
 
 void
-gtk_canvas_box_init (GtkCanvasBox         *self,
-                     const GtkCanvasPoint *point,
-                     const GtkCanvasSize  *size,
-                     float                 origin_x,
-                     float                 origin_y)
+gtk_canvas_box_init (GtkCanvasBox          *self,
+                     const GtkCanvasVec2   *point,
+                     const GtkCanvasVec2   *size,
+                     const graphene_vec2_t *origin)
 {
-  gtk_canvas_point_init_copy (&self->point, point);
-  gtk_canvas_size_init_copy (&self->size, size);
-  self->origin_x = origin_x;
-  self->origin_y = origin_y;
+  gtk_canvas_vec2_init_copy (&self->point, point);
+  gtk_canvas_vec2_init_copy (&self->size, size);
+  graphene_vec2_init_from_vec2 (&self->origin, origin);
 }
 
 void
 gtk_canvas_box_init_copy (GtkCanvasBox       *self,
                           const GtkCanvasBox *source)
 {
-  gtk_canvas_point_init_copy (&self->point, &source->point);
-  gtk_canvas_size_init_copy (&self->size, &source->size);
-  self->origin_x = source->origin_x;
-  self->origin_y = source->origin_y;
+  gtk_canvas_box_init (self, &source->point, &source->size, &source->origin);
 }
 
 void
 gtk_canvas_box_finish (GtkCanvasBox *self)
 {
-  gtk_canvas_point_finish (&self->point);
-  gtk_canvas_size_finish (&self->size);
+  gtk_canvas_vec2_finish (&self->point);
+  gtk_canvas_vec2_finish (&self->size);
 }
 
 /**
@@ -84,15 +76,23 @@ GtkCanvasBox *
 gtk_canvas_box_new_points (const GtkCanvasPoint *point1,
                            const GtkCanvasPoint *point2)
 {
-  GtkCanvasSize size;
+  GtkCanvasVec2 size;
   GtkCanvasBox *result;
+  graphene_vec2_t minus_one;
 
   g_return_val_if_fail (point1 != NULL, NULL);
   g_return_val_if_fail (point2 != NULL, NULL);
 
-  gtk_canvas_size_init_distance (&size, point1, point2);
-  result = gtk_canvas_box_new (point1, &size, 0, 0);
-  gtk_canvas_size_finish (&size);
+  graphene_vec2_init (&minus_one, -1.f, -1.f);
+  gtk_canvas_vec2_init_sum (&size,
+                            graphene_vec2_one (),
+                            point2,
+                            &minus_one,
+                            point1,
+                            NULL);
+  result = g_slice_new (GtkCanvasBox);
+  gtk_canvas_box_init (result, (GtkCanvasVec2 *) point1, &size, graphene_vec2_zero ());
+  gtk_canvas_vec2_finish (&size);
 
   return result;
 }
@@ -118,13 +118,18 @@ gtk_canvas_box_new (const GtkCanvasPoint *point,
                     float                 origin_y)
 {
   GtkCanvasBox *self;
+  graphene_vec2_t origin;
 
   g_return_val_if_fail (point != NULL, NULL);
   g_return_val_if_fail (size != NULL, NULL);
 
-  self = g_slice_new (GtkCanvasBox);
+  graphene_vec2_init (&origin, origin_x, origin_y);
 
-  gtk_canvas_box_init (self, point, size, origin_x, origin_y);
+  self = g_slice_new (GtkCanvasBox);
+  gtk_canvas_box_init (self,
+                       (GtkCanvasVec2 *) point,
+                       (GtkCanvasVec2 *) size,
+                       &origin);
 
   return self;
 }
@@ -132,9 +137,14 @@ gtk_canvas_box_new (const GtkCanvasPoint *point,
 GtkCanvasBox *
 gtk_canvas_box_copy (const GtkCanvasBox *self)
 {
+  GtkCanvasBox *copy;
+
   g_return_val_if_fail (self != NULL, NULL);
 
-  return gtk_canvas_box_new (&self->point, &self->size, self->origin_x, self->origin_y);
+  copy = g_slice_new (GtkCanvasBox);
+  gtk_canvas_box_init_copy (copy, self);
+
+  return copy;
 }
 
 void
@@ -149,15 +159,28 @@ gboolean
 gtk_canvas_box_eval (const GtkCanvasBox *self,
                      graphene_rect_t    *rect)
 {
+  graphene_vec2_t point, size, tmp;
+
   g_return_val_if_fail (self != NULL, FALSE);
   g_return_val_if_fail (rect != NULL, FALSE);
 
-  if (gtk_canvas_point_eval (&self->point, &rect->origin.x, &rect->origin.y) &&
-      gtk_canvas_size_eval (&self->size, &rect->size.width, &rect->size.height))
-    return TRUE;
+  if (!gtk_canvas_vec2_eval (&self->point, &point) ||
+      !gtk_canvas_vec2_eval (&self->size, &size))
+    {
+      *rect = *graphene_rect_zero ();
+      return FALSE;
+    }
+
+  graphene_vec2_multiply (&self->origin, &size, &tmp);
+  graphene_vec2_subtract (&point, &tmp, &point);
+
+  graphene_rect_init (rect,
+                      graphene_vec2_get_x (&point),
+                      graphene_vec2_get_y (&point),
+                      graphene_vec2_get_x (&size),
+                      graphene_vec2_get_y (&size));
 
-  *rect = *graphene_rect_zero ();
-  return FALSE;
+  return TRUE;
 }
 
 const GtkCanvasPoint *
@@ -165,7 +188,7 @@ gtk_canvas_box_get_point (const GtkCanvasBox *self)
 {
   g_return_val_if_fail (self != NULL, NULL);
 
-  return &self->point;
+  return (GtkCanvasPoint *) &self->point;
 }
 
 const GtkCanvasSize *
@@ -173,7 +196,7 @@ gtk_canvas_box_get_size (const GtkCanvasBox *self)
 {
   g_return_val_if_fail (self != NULL, NULL);
 
-  return &self->size;
+  return (GtkCanvasSize *) &self->size;
 }
 
 void
@@ -184,7 +207,7 @@ gtk_canvas_box_get_origin (const GtkCanvasBox *self,
   g_return_if_fail (self != NULL);
 
   if (x)
-    *x = self->origin_x;
+    *x = graphene_vec2_get_x (&self->origin);
   if (y)
-    *y = self->origin_y;
+    *y = graphene_vec2_get_y (&self->origin);
 }
diff --git a/gtk/gtkcanvasboxprivate.h b/gtk/gtkcanvasboxprivate.h
index 82baa5fb2a..99e7e7f084 100644
--- a/gtk/gtkcanvasboxprivate.h
+++ b/gtk/gtkcanvasboxprivate.h
@@ -3,25 +3,22 @@
 
 #include "gtkcanvasbox.h"
 
-#include "gtkcanvaspointprivate.h"
-#include "gtkcanvassizeprivate.h"
+#include "gtkcanvasvec2private.h"
 
 G_BEGIN_DECLS
 
 struct _GtkCanvasBox
 {
-  GtkCanvasPoint point;
-  GtkCanvasSize size;
-  float origin_x;
-  float origin_y;
+  GtkCanvasVec2 point;
+  GtkCanvasVec2 size;
+  graphene_vec2_t origin;
 };
 
 
 void                    gtk_canvas_box_init                     (GtkCanvasBox           *self,
-                                                                 const GtkCanvasPoint   *point,
-                                                                 const GtkCanvasSize    *size,
-                                                                 float                   origin_x,
-                                                                 float                   origin_y);
+                                                                 const GtkCanvasVec2    *point,
+                                                                 const GtkCanvasVec2    *size,
+                                                                 const graphene_vec2_t  *origin);
 void                    gtk_canvas_box_init_copy                (GtkCanvasBox           *self,
                                                                  const GtkCanvasBox     *source);
 void                    gtk_canvas_box_finish                   (GtkCanvasBox           *self);
diff --git a/gtk/gtkcanvasitem.c b/gtk/gtkcanvasitem.c
index 1a56374a9b..b5def0b8ba 100644
--- a/gtk/gtkcanvasitem.c
+++ b/gtk/gtkcanvasitem.c
@@ -23,8 +23,6 @@
 
 #include "gtkcanvas.h"
 #include "gtkcanvasboxprivate.h"
-#include "gtkcanvaspointprivate.h"
-#include "gtkcanvassizeprivate.h"
 #include "gtkintl.h"
 #include "gtklistitemfactoryprivate.h"
 #include "gtkwidget.h"
@@ -44,6 +42,8 @@ struct _GtkCanvasItem
   gpointer item;
   GtkWidget *widget;
   GtkCanvasBox bounds;
+
+  GtkCanvasVec2 size_vecs[4];
 };
 
 enum
@@ -77,6 +77,18 @@ gtk_canvas_item_dispose (GObject *object)
   G_OBJECT_CLASS (gtk_canvas_item_parent_class)->dispose (object);
 }
 
+static void
+gtk_canvas_item_finalize (GObject *object)
+{
+  GtkCanvasItem *self = GTK_CANVAS_ITEM (object);
+  int i;
+
+  for (i = 0; i < 4; i++)
+    gtk_canvas_vec2_finish (&self->size_vecs[i]);
+
+  G_OBJECT_CLASS (gtk_canvas_item_parent_class)->finalize (object);
+}
+
 static void
 gtk_canvas_item_get_property (GObject    *object,
                               guint       property_id,
@@ -139,6 +151,7 @@ gtk_canvas_item_class_init (GtkCanvasItemClass *klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
   gobject_class->dispose = gtk_canvas_item_dispose;
+  gobject_class->finalize = gtk_canvas_item_finalize;
   gobject_class->get_property = gtk_canvas_item_get_property;
   gobject_class->set_property = gtk_canvas_item_set_property;
 
@@ -188,14 +201,14 @@ gtk_canvas_item_class_init (GtkCanvasItemClass *klass)
 static void
 gtk_canvas_item_init (GtkCanvasItem *self)
 {
-  GtkCanvasPoint point;
-  GtkCanvasSize size;
-
-  gtk_canvas_point_init (&point, 0, 0);
-  gtk_canvas_size_init_measure_item (&size, self, GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT);
-  gtk_canvas_box_init (&self->bounds, &point, &size, 0, 0);
-  gtk_canvas_size_finish (&size);
-  gtk_canvas_point_finish (&point);
+  int i;
+
+  for (i = 0; i < 4; i++)
+    gtk_canvas_vec2_init_variable (&self->size_vecs[i]);
+
+  gtk_canvas_vec2_init_constant (&self->bounds.point, 0, 0);
+  gtk_canvas_vec2_init_copy (&self->bounds.size, &self->size_vecs[GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT]);
+  graphene_vec2_init (&self->bounds.origin, 0, 0);
 }
 
 GtkCanvasItem *
@@ -215,6 +228,51 @@ gtk_canvas_item_new (GtkCanvas *canvas,
   return self;
 }
 
+void
+gtk_canvas_item_validate_variables (GtkCanvasItem *self)
+{
+  int w[4], h[4], i;
+
+  if (self->widget == NULL)
+    {
+      memset (w, 0, sizeof (w));
+      memset (h, 0, sizeof (h));
+    }
+  else
+    {
+      if (gtk_widget_get_request_mode (self->widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+        {
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_HORIZONTAL, -1, &w[0], &w[2], NULL, NULL);
+          w[1] = w[0];
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_VERTICAL, w[0], &h[0], &h[1], NULL, NULL);
+          w[3] = w[2];
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_VERTICAL, w[2], &h[2], &h[3], NULL, NULL);
+        }
+      else
+        {
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_VERTICAL, -1, &h[0], &h[2], NULL, NULL);
+          h[1] = h[0];
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_HORIZONTAL, h[0], &w[0], &w[1], NULL, NULL);
+          h[3] = h[2];
+          gtk_widget_measure (self->widget, GTK_ORIENTATION_HORIZONTAL, h[2], &w[2], &w[3], NULL, NULL);
+        }
+    }
+
+  for (i = 0; i < 4; i++)
+    {
+      gtk_canvas_vec2_init_constant (
+          gtk_canvas_vec2_get_variable (&self->size_vecs[i]),
+          0, 0);
+    }
+}
+
+const GtkCanvasVec2 *
+gtk_canvas_item_get_measure_vec2 (GtkCanvasItem            *self,
+                                  GtkCanvasItemMeasurement  measure)
+{
+  return &self->size_vecs[measure];
+}
+
 /**
  * gtk_canvas_item_get_canvas: (attributes org.gtk.Method.get_property=canvas)
  * @self: a `GtkCanvasItem`
diff --git a/gtk/gtkcanvasitemprivate.h b/gtk/gtkcanvasitemprivate.h
index f22916e925..49724204ff 100644
--- a/gtk/gtkcanvasitemprivate.h
+++ b/gtk/gtkcanvasitemprivate.h
@@ -3,11 +3,18 @@
 
 #include "gtkcanvasitem.h"
 
+#include "gtkcanvassize.h"
+#include "gtkcanvasvec2private.h"
+
 G_BEGIN_DECLS
 
 GtkCanvasItem *         gtk_canvas_item_new                      (GtkCanvas             *canvas,
                                                                   gpointer               item);
 
+void                    gtk_canvas_item_validate_variables       (GtkCanvasItem         *self);
+const GtkCanvasVec2 *   gtk_canvas_item_get_measure_vec2         (GtkCanvasItem         *self,
+                                                                  GtkCanvasItemMeasurement measure);
+
 void                    gtk_canvas_item_clear_canvas             (GtkCanvasItem         *self);
 
 void                    gtk_canvas_item_setup                    (GtkCanvasItem         *self,
diff --git a/gtk/gtkcanvaspoint.c b/gtk/gtkcanvaspoint.c
index df812b5cf4..e5536ebc7a 100644
--- a/gtk/gtkcanvaspoint.c
+++ b/gtk/gtkcanvaspoint.c
@@ -26,121 +26,24 @@
 
 #include "config.h"
 
-#include "gtkcanvaspointprivate.h"
+#include "gtkcanvaspoint.h"
 
-#include "gtkcanvasbox.h"
-
-/* {{{ Boilerplate */
-
-struct _GtkCanvasPointClass
-{
-  const char *type_name;
-
-  void                  (* copy)                (GtkCanvasPoint         *self,
-                                                 const GtkCanvasPoint   *source);
-  void                  (* finish)              (GtkCanvasPoint         *self);
-  gboolean              (* eval)                (const GtkCanvasPoint   *self,
-                                                 float                  *x,
-                                                 float                  *y);
-};
+#include "gtkcanvasboxprivate.h"
+#include "gtkcanvasvec2private.h"
 
 G_DEFINE_BOXED_TYPE (GtkCanvasPoint, gtk_canvas_point,
                      gtk_canvas_point_copy,
                      gtk_canvas_point_free)
 
-static gpointer
-gtk_canvas_point_alloc (const GtkCanvasPointClass *class)
-{
-  GtkCanvasPoint *self = g_slice_new (GtkCanvasPoint);
-
-  self->class = class;
-
-  return self;
-}
-
-void
-gtk_canvas_point_init_copy (GtkCanvasPoint       *self,
-                            const GtkCanvasPoint *source)
-{
-  self->class = source->class;
-  self->class->copy (self, source);
-}
-
-void
-gtk_canvas_point_finish (GtkCanvasPoint *self)
-{
-  self->class->finish (self);
-}
-
-/* }}} */
-/* {{{ OFFSET */
-
-static void
-gtk_canvas_point_offset_copy (GtkCanvasPoint       *point,
-                              const GtkCanvasPoint *source_point)
+struct _GtkCanvasPoint
 {
-  GtkCanvasPointOffset *self = &point->offset;
-  const GtkCanvasPointOffset *source = &source_point->offset;
-
-  *self = *source;
-
-  if (source->other)
-    self->other = gtk_canvas_point_copy (source->other);
-}
-
-static void
-gtk_canvas_point_offset_finish (GtkCanvasPoint *point)
-{
-  GtkCanvasPointOffset *self = &point->offset;
-
-  if (self->other)
-    gtk_canvas_point_free (self->other);
-}
-
-static gboolean
-gtk_canvas_point_offset_eval (const GtkCanvasPoint *point,
-                              float                *x,
-                              float                *y)
-{
-  const GtkCanvasPointOffset *self = &point->offset;
-
-  if (self->other != NULL)
-    {
-      if (!gtk_canvas_point_eval (self->other, x, y))
-        return FALSE;
-
-      *x += self->dx;
-      *y += self->dy;
-    }
-  else
-    {
-      *x = self->dx;
-      *y = self->dy;
-    }
-
-  return TRUE;
-}
-
-static const GtkCanvasPointClass GTK_CANVAS_POINT_OFFSET_CLASS =
-{
-  "GtkCanvasPointOffset",
-  gtk_canvas_point_offset_copy,
-  gtk_canvas_point_offset_finish,
-  gtk_canvas_point_offset_eval,
+  GtkCanvasVec2 vec2;
 };
 
-void
-gtk_canvas_point_init (GtkCanvasPoint *point,
-                       float           x,
-                       float           y)
+static GtkCanvasPoint *
+gtk_canvas_point_alloc (void)
 {
-  GtkCanvasPointOffset *self = &point->offset;
-
-  self->class = &GTK_CANVAS_POINT_OFFSET_CLASS;
-
-  self->other = NULL;
-  self->dx = x;
-  self->dy = y;
+  return g_slice_new (GtkCanvasPoint);
 }
 
 /**
@@ -158,68 +61,17 @@ gtk_canvas_point_new (float x,
 {
   GtkCanvasPoint *self;
 
-  self = gtk_canvas_point_alloc (&GTK_CANVAS_POINT_OFFSET_CLASS);
-
-  gtk_canvas_point_init (self, x, y);
+  self = gtk_canvas_point_alloc ();
+  gtk_canvas_vec2_init_constant (&self->vec2, x, y);
 
   return self;
 }
 
-/* }}} */
-/* {{{ BOX */
-
-static void
-gtk_canvas_point_box_copy (GtkCanvasPoint       *point,
-                           const GtkCanvasPoint *source_point)
-{
-  GtkCanvasPointBox *self = &point->box;
-  const GtkCanvasPointBox *source = &source_point->box;
-
-  *self = *source;
-
-  self->box = gtk_canvas_box_copy (source->box);
-}
-
-static void
-gtk_canvas_point_box_finish (GtkCanvasPoint *point)
-{
-  GtkCanvasPointBox *self = &point->box;
-
-  gtk_canvas_box_free (self->box);
-}
-
-static gboolean
-gtk_canvas_point_box_eval (const GtkCanvasPoint *point,
-                           float                *x,
-                           float                *y)
-{
-  const GtkCanvasPointBox *self = &point->box;
-  graphene_rect_t rect;
-
-  if (!gtk_canvas_box_eval (self->box, &rect))
-    return FALSE;
-
-  *x = rect.origin.x + self->offset_x + self->origin_x * rect.size.width;
-  *y = rect.origin.y + self->offset_y + self->origin_y * rect.size.height;
-
-  return TRUE;
-}
-
-static const GtkCanvasPointClass GTK_CANVAS_POINT_BOX_CLASS =
-{
-  "GtkCanvasPointBox",
-  gtk_canvas_point_box_copy,
-  gtk_canvas_point_box_finish,
-  gtk_canvas_point_box_eval,
-};
-
 /**
  * gtk_canvas_point_new_from_box:
  * @box: a box
  * @origin_x: x coordinate of box origin
  * @origin_y: y coordinate of box origin
- * @offset_x: offset in x direction
- * @offset_y: offset in y direction
  *
  * Creates a point relative to the given box.
  *
@@ -227,35 +79,31 @@ static const GtkCanvasPointClass GTK_CANVAS_POINT_BOX_CLASS =
  * (0, 0) being the top left and (1, 1) being the bottom right
  * corner of the box.
  *
- * The offset is then added to the origin. It may be negative.
- *
  * Returns: a new point
  **/
 GtkCanvasPoint *
 gtk_canvas_point_new_from_box (const GtkCanvasBox *box,
                                float               origin_x,
-                               float               origin_y,
-                               float               offset_x,
-                               float               offset_y)
+                               float               origin_y)
 {
-  GtkCanvasPointBox *self;
-
+  GtkCanvasPoint *self;
+  graphene_vec2_t origin;
+ 
   g_return_val_if_fail (box != NULL, NULL);
-
-  self = gtk_canvas_point_alloc (&GTK_CANVAS_POINT_BOX_CLASS);
-
-  self->box = gtk_canvas_box_copy (box);
-  self->origin_x = origin_x;
-  self->origin_y = origin_y;
-  self->offset_x = offset_x;
-  self->offset_y = offset_y;
-
-  return (GtkCanvasPoint *) self;
+ 
+  graphene_vec2_init (&origin, origin_x, origin_y);
+  graphene_vec2_subtract (&origin, &box->origin, &origin);
+ 
+  self = gtk_canvas_point_alloc ();
+  gtk_canvas_vec2_init_sum (&self->vec2,
+                            graphene_vec2_one (),
+                            &box->point,
+                            &origin,
+                            &box->size,
+                            NULL);
+  return self;
 }
 
-/* }}} */
-/* {{{ PUBLIC API */
-
 GtkCanvasPoint *
 gtk_canvas_point_copy (const GtkCanvasPoint *self)
 {
@@ -263,9 +111,8 @@ gtk_canvas_point_copy (const GtkCanvasPoint *self)
 
   g_return_val_if_fail (self != NULL, NULL);
 
-  copy = gtk_canvas_point_alloc (self->class);
-
-  gtk_canvas_point_init_copy (copy, self);
+  copy = gtk_canvas_point_alloc ();
+  gtk_canvas_vec2_init_copy (&copy->vec2, &self->vec2);
 
   return copy;
 }
@@ -273,7 +120,7 @@ gtk_canvas_point_copy (const GtkCanvasPoint *self)
 void
 gtk_canvas_point_free (GtkCanvasPoint *self)
 {
-  gtk_canvas_point_finish (self);
+  gtk_canvas_vec2_finish (&self->vec2);
 
   g_slice_free (GtkCanvasPoint, self);
 }
@@ -283,15 +130,21 @@ gtk_canvas_point_eval (const GtkCanvasPoint *self,
                        float                *x,
                        float                *y)
 {
+  graphene_vec2_t vec2;
+
   g_return_val_if_fail (self != NULL, FALSE);
   g_return_val_if_fail (x != NULL, FALSE);
   g_return_val_if_fail (y != NULL, FALSE);
 
-  if (self->class->eval (self, x, y))
-    return TRUE;
+  if (!gtk_canvas_vec2_eval (&self->vec2, &vec2))
+    {
+      *x = 0;
+      *y = 0;
+      return FALSE;
+    }
 
-  *x = 0;
-  *y = 0;
-  return FALSE;
+  *x = graphene_vec2_get_x (&vec2);
+  *y = graphene_vec2_get_y (&vec2);
+  return TRUE;
 }
 
diff --git a/gtk/gtkcanvaspoint.h b/gtk/gtkcanvaspoint.h
index 5a35ba3423..f59db58e1a 100644
--- a/gtk/gtkcanvaspoint.h
+++ b/gtk/gtkcanvaspoint.h
@@ -50,9 +50,7 @@ GtkCanvasPoint *        gtk_canvas_point_new                    (float
 GDK_AVAILABLE_IN_ALL
 GtkCanvasPoint *        gtk_canvas_point_new_from_box           (const GtkCanvasBox     *box,
                                                                  float                   origin_x,
-                                                                 float                   origin_y,
-                                                                 float                   offset_x,
-                                                                 float                   offset_y);
+                                                                 float                   origin_y);
 GDK_AVAILABLE_IN_ALL
 GtkCanvasPoint *        gtk_canvas_point_new_from_item          (GtkCanvasItem          *item,
                                                                  float                   origin_x,
diff --git a/gtk/gtkcanvassize.c b/gtk/gtkcanvassize.c
index 81fcba2d19..a706def6af 100644
--- a/gtk/gtkcanvassize.c
+++ b/gtk/gtkcanvassize.c
@@ -26,94 +26,28 @@
 
 #include "config.h"
 
-#include "gtkcanvassizeprivate.h"
+#include "gtkcanvassize.h"
 
-#include "gtkcanvasbox.h"
-#include "gtkcanvasitem.h"
+#include "gtkcanvasboxprivate.h"
+#include "gtkcanvasitemprivate.h"
 #include "gtkcanvaspoint.h"
-#include "gtkwidget.h"
-
-/* {{{ Boilerplate */
-
-struct _GtkCanvasSizeClass
-{
-  const char *type_name;
-
-  void                  (* copy)                (GtkCanvasSize          *self,
-                                                 const GtkCanvasSize    *source);
-  void                  (* finish)              (GtkCanvasSize          *self);
-  gboolean              (* eval)                (const GtkCanvasSize    *self,
-                                                 float                  *width,
-                                                 float                  *height);
-};
+#include "gtkcanvasvec2private.h"
 
 G_DEFINE_BOXED_TYPE (GtkCanvasSize, gtk_canvas_size,
                      gtk_canvas_size_copy,
                      gtk_canvas_size_free)
 
-static gpointer
-gtk_canvas_size_alloc (const GtkCanvasSizeClass *class)
-{
-  GtkCanvasSize *self = g_slice_new (GtkCanvasSize);
-
-  self->class = class;
-
-  return self;
-}
-
-void
-gtk_canvas_size_init_copy (GtkCanvasSize       *self,
-                           const GtkCanvasSize *source)
-{
-  self->class = source->class;
-  self->class->copy (self, source);
-}
-
-void
-gtk_canvas_size_finish (GtkCanvasSize *self)
-{
-  self->class->finish (self);
-}
-
-/* }}} */
-/* {{{ ABSOLUTE */
-
-static void
-gtk_canvas_size_absolute_copy (GtkCanvasSize       *size,
-                               const GtkCanvasSize *source_size)
+struct _GtkCanvasSize
 {
-  GtkCanvasSizeAbsolute *self = &size->absolute;
-  const GtkCanvasSizeAbsolute *source = &source_size->absolute;
-
-  *self = *source;
-}
-
-static void
-gtk_canvas_size_absolute_finish (GtkCanvasSize *size)
-{
-}
+  GtkCanvasVec2 vec2;
+};
 
-static gboolean
-gtk_canvas_size_absolute_eval (const GtkCanvasSize *size,
-                               float               *width,
-                               float               *height)
+static GtkCanvasSize *
+gtk_canvas_size_alloc (void)
 {
-  const GtkCanvasSizeAbsolute *self = &size->absolute;
-
-  *width = self->width;
-  *height = self->height;
-
-  return TRUE;
+  return g_slice_new (GtkCanvasSize);
 }
 
-static const GtkCanvasSizeClass GTK_CANVAS_SIZE_ABSOLUTE_CLASS =
-{
-  "GtkCanvasSizeAbsolute",
-  gtk_canvas_size_absolute_copy,
-  gtk_canvas_size_absolute_finish,
-  gtk_canvas_size_absolute_eval,
-};
-
 /**
  * gtk_canvas_size_new:
  * @width: width of the size
@@ -127,63 +61,14 @@ GtkCanvasSize *
 gtk_canvas_size_new (float width,
                      float height)
 {
-  GtkCanvasSizeAbsolute *self;
-
-  self = gtk_canvas_size_alloc (&GTK_CANVAS_SIZE_ABSOLUTE_CLASS);
-  self->width = width;
-  self->height = height;
-
-  return (GtkCanvasSize *) self;
-}
-
-/* }}} */
-/* {{{ BOX */
-
-static void
-gtk_canvas_size_box_copy (GtkCanvasSize       *size,
-                          const GtkCanvasSize *source_size)
-{
-  GtkCanvasSizeBox *self = &size->box;
-  const GtkCanvasSizeBox *source = &source_size->box;
-
-  *self = *source;
-
-  self->box = gtk_canvas_box_copy (source->box);
-}
-
-static void
-gtk_canvas_size_box_finish (GtkCanvasSize *size)
-{
-  GtkCanvasSizeBox *self = &size->box;
-
-  gtk_canvas_box_free (self->box);
-}
-
-static gboolean
-gtk_canvas_size_box_eval (const GtkCanvasSize *size,
-                          float               *width,
-                          float               *height)
-{
-  const GtkCanvasSizeBox *self = &size->box;
-  graphene_rect_t rect;
-
-  if (!gtk_canvas_box_eval (self->box, &rect))
-    return FALSE;
+  GtkCanvasSize *self;
 
-  *width = rect.size.width;
-  *height = rect.size.height;
+  self = gtk_canvas_size_alloc ();
+  gtk_canvas_vec2_init_constant (&self->vec2, width, height);
 
-  return TRUE;
+  return self;
 }
 
-static const GtkCanvasSizeClass GTK_CANVAS_SIZE_BOX_CLASS =
-{
-  "GtkCanvasSizeBox",
-  gtk_canvas_size_box_copy,
-  gtk_canvas_size_box_finish,
-  gtk_canvas_size_box_eval,
-};
-
 /**
  * gtk_canvas_size_new_from_box:
  * @box: a box
@@ -195,76 +80,12 @@ static const GtkCanvasSizeClass GTK_CANVAS_SIZE_BOX_CLASS =
 GtkCanvasSize *
 gtk_canvas_size_new_from_box (const GtkCanvasBox *box)
 {
-  GtkCanvasSizeBox *self;
-
-  g_return_val_if_fail (box != NULL, NULL);
-
-  self = gtk_canvas_size_alloc (&GTK_CANVAS_SIZE_BOX_CLASS);
-
-  /* FIXME: We could potentially just copy the box's size here */
-  self->box = gtk_canvas_box_copy (box);
-
-  return (GtkCanvasSize *) self;
-}
-
-/* }}} */
-/* {{{ DISTANCE */
-
-static void
-gtk_canvas_size_distance_copy (GtkCanvasSize       *size,
-                               const GtkCanvasSize *source_size)
-{
-  const GtkCanvasSizeDistance *source = &source_size->distance;
-
-  gtk_canvas_size_init_distance (size, source->from, source->to);
-}
-
-static void
-gtk_canvas_size_distance_finish (GtkCanvasSize *size)
-{
-  GtkCanvasSizeDistance *self = &size->distance;
-
-  gtk_canvas_point_free (self->from);
-  gtk_canvas_point_free (self->to);
-}
-
-static gboolean
-gtk_canvas_size_distance_eval (const GtkCanvasSize *size,
-                               float               *width,
-                               float               *height)
-{
-  const GtkCanvasSizeDistance *self = &size->distance;
-  float x1, y1, x2, y2;
-
-  if (!gtk_canvas_point_eval (self->from, &x1, &y1) ||
-      !gtk_canvas_point_eval (self->from, &x2, &y2))
-    return FALSE;
-
-  *width = x1 - x2;
-  *height = y1 - y2;
-
-  return TRUE;
-}
-
-static const GtkCanvasSizeClass GTK_CANVAS_SIZE_DISTANCE_CLASS =
-{
-  "GtkCanvasSizeDistance",
-  gtk_canvas_size_distance_copy,
-  gtk_canvas_size_distance_finish,
-  gtk_canvas_size_distance_eval,
-};
+  GtkCanvasSize *self;
 
-void
-gtk_canvas_size_init_distance (GtkCanvasSize        *size,
-                               const GtkCanvasPoint *from,
-                               const GtkCanvasPoint *to)
-{
-  GtkCanvasSizeDistance *self = &size->distance;
-  
-  self->class = &GTK_CANVAS_SIZE_DISTANCE_CLASS;
+  self = gtk_canvas_size_alloc ();
+  gtk_canvas_vec2_init_copy (&self->vec2, &box->size);
 
-  self->from = gtk_canvas_point_copy (from);
-  self->to = gtk_canvas_point_copy (to);
+  return self;
 }
 
 /**
@@ -273,7 +94,8 @@ gtk_canvas_size_init_distance (GtkCanvasSize        *size,
  * @to: point to where to compute the distance
  *
  * Creates a size for the given distance. Note that both width and height
- * can be negative if @to is smaller than @from in the corresponding dimension.
+ * can be negative if the coordinate of @to is smaller than @from in the
+ * corresponding dimension.
  *
  * Returns: a new size
  **/
@@ -282,134 +104,24 @@ gtk_canvas_size_new_distance (const GtkCanvasPoint *from,
                               const GtkCanvasPoint *to)
 {
   GtkCanvasSize *self;
+  graphene_vec2_t minus_one;
 
   g_return_val_if_fail (from != NULL, NULL);
   g_return_val_if_fail (to != NULL, NULL);
 
-  self = gtk_canvas_size_alloc (&GTK_CANVAS_SIZE_DISTANCE_CLASS);
+  graphene_vec2_init (&minus_one, -1.f, -1.f);
 
-  gtk_canvas_size_init_distance (self, from, to);
+  self = gtk_canvas_size_alloc ();
+  gtk_canvas_vec2_init_sum (&self->vec2,
+                            graphene_vec2_one (),
+                            from,
+                            &minus_one,
+                            to,
+                            NULL);
 
   return self;
 }
 
-/* }}} */
-/* {{{ MEASURE */
-
-static void
-gtk_canvas_size_measure_copy (GtkCanvasSize       *size,
-                              const GtkCanvasSize *source_size)
-{
-  const GtkCanvasSizeMeasure *source = &source_size->measure;
-
-  gtk_canvas_size_init_measure_item (size, source->item, source->measure);
-}
-
-static void
-gtk_canvas_size_measure_finish (GtkCanvasSize *size)
-{
-}
-
-static gboolean
-gtk_canvas_size_measure_eval (const GtkCanvasSize *size,
-                              float               *width,
-                              float               *height)
-{
-  const GtkCanvasSizeMeasure *self = &size->measure;
-  GtkWidget *widget;
-  int w, h;
-
-  if (self->item == NULL)
-    return FALSE;
-
-  widget = gtk_canvas_item_get_widget (self->item);
-  if (widget == NULL)
-    {
-      *width = 0;
-      *height = 0;
-      return TRUE;
-    }
-
-  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
-    {
-      switch (self->measure)
-      {
-        case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN:
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_NAT:
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &w, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_MIN:
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, NULL, &h, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT:
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &w, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, NULL, &h, NULL, NULL);
-          break;
-        default:
-          g_assert_not_reached ();
-          w = h = 0;
-          break;
-      }
-    }
-  else
-    {
-      switch (self->measure)
-      {
-        case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN:
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_NAT:
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, NULL, &h, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_MIN:
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, NULL, &w, NULL, NULL);
-          break;
-        case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT:
-          gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, NULL, &h, NULL, NULL);
-          gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, NULL, &w, NULL, NULL);
-          break;
-        default:
-          g_assert_not_reached ();
-          w = h = 0;
-          break;
-      }
-    }
-
-  *width = w;
-  *height = h;
-
-  return TRUE;
-}
-
-static const GtkCanvasSizeClass GTK_CANVAS_SIZE_MEASURE_CLASS =
-{
-  "GtkCanvasSizeMeasure",
-  gtk_canvas_size_measure_copy,
-  gtk_canvas_size_measure_finish,
-  gtk_canvas_size_measure_eval,
-};
-
-void
-gtk_canvas_size_init_measure_item (GtkCanvasSize            *size,
-                                   GtkCanvasItem            *item,
-                                   GtkCanvasItemMeasurement  measure)
-{
-  GtkCanvasSizeMeasure *self = &size->measure;
-
-  self->class = &GTK_CANVAS_SIZE_MEASURE_CLASS;
-  
-  self->item = item;
-  self->measure = measure;
-}
-
 /**
  * gtk_canvas_size_new_measure_item:
  * @item: the item
@@ -428,68 +140,13 @@ gtk_canvas_size_new_measure_item (GtkCanvasItem            *item,
 
   g_return_val_if_fail (GTK_IS_CANVAS_ITEM (item), NULL);
 
-  self = gtk_canvas_size_alloc (&GTK_CANVAS_SIZE_MEASURE_CLASS);
-
-  gtk_canvas_size_init_measure_item (self, item, measure);
+  self = gtk_canvas_size_alloc ();
+  gtk_canvas_vec2_init_copy (&self->vec2,
+                             gtk_canvas_item_get_measure_vec2 (item, measure));
 
   return self;
 }
 
-/* }}} */
-/* {{{ REFERENCE */
-
-static void
-gtk_canvas_size_reference_copy (GtkCanvasSize       *size,
-                                const GtkCanvasSize *source_size)
-{
-  const GtkCanvasSizeReference *source = &source_size->reference;
-
-  gtk_canvas_size_init_reference (size, g_rc_box_acquire (source->reference));
-}
-
-static void
-gtk_canvas_size_reference_finish (GtkCanvasSize *size)
-{
-  const GtkCanvasSizeReference *self = &size->reference;
-
-  g_rc_box_release (self->reference);
-}
-
-static gboolean
-gtk_canvas_size_reference_eval (const GtkCanvasSize *size,
-                                float               *width,
-                                float               *height)
-{
-  const GtkCanvasSizeReference *self = &size->reference;
-
-  *width = self->reference->width;
-  *height = self->reference->height;
-
-  return TRUE;
-}
-
-static const GtkCanvasSizeClass GTK_CANVAS_SIZE_REFERENCE_CLASS =
-{
-  "GtkCanvasSizeReference",
-  gtk_canvas_size_reference_copy,
-  gtk_canvas_size_reference_finish,
-  gtk_canvas_size_reference_eval,
-};
-
-void
-gtk_canvas_size_init_reference (GtkCanvasSize   *size,
-                                graphene_size_t *reference)
-{
-  GtkCanvasSizeReference *self = &size->reference;
-
-  self->class = &GTK_CANVAS_SIZE_REFERENCE_CLASS;
-  
-  self->reference = reference;
-}
-
-/* }}} */
-/* {{{ PUBLIC API */
-
 GtkCanvasSize *
 gtk_canvas_size_copy (const GtkCanvasSize *self)
 {
@@ -497,9 +154,8 @@ gtk_canvas_size_copy (const GtkCanvasSize *self)
 
   g_return_val_if_fail (self != NULL, NULL);
 
-  copy = gtk_canvas_size_alloc (self->class);
-
-  gtk_canvas_size_init_copy (copy, self);
+  copy = gtk_canvas_size_alloc ();
+  gtk_canvas_vec2_init_copy (&copy->vec2, &self->vec2);
 
   return copy;
 }
@@ -507,7 +163,9 @@ gtk_canvas_size_copy (const GtkCanvasSize *self)
 void
 gtk_canvas_size_free (GtkCanvasSize *self)
 {
-  gtk_canvas_size_finish (self);
+  g_return_if_fail (self != NULL);
+
+  gtk_canvas_vec2_finish (&self->vec2);
 
   g_slice_free (GtkCanvasSize, self);
 }
@@ -517,15 +175,21 @@ gtk_canvas_size_eval (const GtkCanvasSize *self,
                       float                *width,
                       float                *height)
 {
+  graphene_vec2_t vec2;
+
   g_return_val_if_fail (self != NULL, FALSE);
   g_return_val_if_fail (width != NULL, FALSE);
   g_return_val_if_fail (height != NULL, FALSE);
 
-  if (self->class->eval (self, width, height))
-    return TRUE;
+  if (!gtk_canvas_vec2_eval (&self->vec2, &vec2))
+    {
+      *width = 0;
+      *height = 0;
+      return FALSE;
+    }
 
-  *width = 0;
-  *height = 0;
-  return FALSE;
+  *width = graphene_vec2_get_x (&vec2);
+  *height = graphene_vec2_get_y (&vec2);
+  return TRUE;
 }
 
diff --git a/gtk/gtkcanvasvec2.c b/gtk/gtkcanvasvec2.c
new file mode 100644
index 0000000000..dfba1b10b0
--- /dev/null
+++ b/gtk/gtkcanvasvec2.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright © 2022 Benjamin Otte
+ *
+ * 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.1 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+
+/**
+ * GtkCanvasVec2:
+ *
+ * `GtkCanvasVec2` describes a vec2 in a `GtkCanvas`.
+ */
+
+#include "config.h"
+
+#include "gtkcanvasvec2private.h"
+
+/* {{{ Boilerplate */
+
+struct _GtkCanvasVec2Class
+{
+  const char *type_name;
+
+  void                  (* copy)                (GtkCanvasVec2          *self,
+                                                 const GtkCanvasVec2    *source);
+  void                  (* finish)              (GtkCanvasVec2          *self);
+  gboolean              (* eval)                (const GtkCanvasVec2    *self,
+                                                 graphene_vec2_t        *result);
+};
+
+/* }}} */
+/* {{{ INVALID */
+
+static void
+gtk_canvas_vec2_invalid_copy (GtkCanvasVec2       *vec2,
+                              const GtkCanvasVec2 *source_vec2)
+{
+  gtk_canvas_vec2_init_invalid (vec2);
+}
+
+static void
+gtk_canvas_vec2_invalid_finish (GtkCanvasVec2 *vec2)
+{
+}
+
+static gboolean
+gtk_canvas_vec2_invalid_eval (const GtkCanvasVec2 *vec2,
+                              graphene_vec2_t     *result)
+{
+  return FALSE;
+}
+
+static const GtkCanvasVec2Class GTK_CANVAS_VEC2_INVALID_CLASS =
+{
+  "GtkCanvasVec2Invalid",
+  gtk_canvas_vec2_invalid_copy,
+  gtk_canvas_vec2_invalid_finish,
+  gtk_canvas_vec2_invalid_eval,
+};
+
+void
+gtk_canvas_vec2_init_invalid (GtkCanvasVec2 *vec2)
+{
+  vec2->class = &GTK_CANVAS_VEC2_INVALID_CLASS;
+}
+
+/* }}} */
+/* {{{ CONSTANT */
+
+static void
+gtk_canvas_vec2_constant_copy (GtkCanvasVec2       *vec2,
+                               const GtkCanvasVec2 *source_vec2)
+{
+  const GtkCanvasVec2Constant *source = &source_vec2->constant;
+
+  gtk_canvas_vec2_init_constant_from_vec2 (vec2, &source->value);
+}
+
+static void
+gtk_canvas_vec2_constant_finish (GtkCanvasVec2 *vec2)
+{
+}
+
+static gboolean
+gtk_canvas_vec2_constant_eval (const GtkCanvasVec2 *vec2,
+                               graphene_vec2_t     *result)
+{
+  const GtkCanvasVec2Constant *self = &vec2->constant;
+
+  graphene_vec2_init_from_vec2 (result, &self->value);
+
+  return TRUE;
+}
+
+static const GtkCanvasVec2Class GTK_CANVAS_VEC2_CONSTANT_CLASS =
+{
+  "GtkCanvasVec2Constant",
+  gtk_canvas_vec2_constant_copy,
+  gtk_canvas_vec2_constant_finish,
+  gtk_canvas_vec2_constant_eval,
+};
+
+void
+gtk_canvas_vec2_init_constant_from_vec2 (GtkCanvasVec2         *vec2,
+                                         const graphene_vec2_t *value)
+{
+  GtkCanvasVec2Constant *self = &vec2->constant;
+
+  self->class = &GTK_CANVAS_VEC2_CONSTANT_CLASS;
+  graphene_vec2_init_from_vec2 (&self->value, value);
+}
+
+void
+gtk_canvas_vec2_init_constant (GtkCanvasVec2 *vec2,
+                               float          x,
+                               float          y)
+{
+  graphene_vec2_t v;
+
+  graphene_vec2_init (&v, x, y);
+  gtk_canvas_vec2_init_constant_from_vec2 (vec2, &v);
+}
+
+/* }}} */
+/* {{{ SUM */
+
+static void
+gtk_canvas_vec2_sum_copy (GtkCanvasVec2       *vec2,
+                          const GtkCanvasVec2 *source_vec2);
+
+static void
+gtk_canvas_vec2_sum_finish (GtkCanvasVec2 *vec2)
+{
+  GtkCanvasVec2Sum *self = &vec2->sum;
+  gsize i;
+
+  for (i = 0; i < self->n_summands; i++)
+    {
+      gtk_canvas_vec2_finish (&self->summands[i].value);
+    }
+
+  g_free (self->summands);
+}
+
+static gboolean
+gtk_canvas_vec2_sum_eval (const GtkCanvasVec2 *vec2,
+                          graphene_vec2_t     *result)
+{
+  const GtkCanvasVec2Sum *self = &vec2->sum;
+  gsize i;
+
+  if (!gtk_canvas_vec2_eval (&self->summands[0].value, result))
+    return FALSE;
+  graphene_vec2_multiply (&self->summands[0].scale, result, result);
+
+  for (i = 1; i < self->n_summands; i++)
+    {
+      graphene_vec2_t tmp;
+
+      if (!gtk_canvas_vec2_eval (&self->summands[i].value, &tmp))
+        return FALSE;
+      graphene_vec2_multiply (&self->summands[i].scale, &tmp, &tmp);
+      graphene_vec2_add (&tmp, result, result);
+    }
+
+  return TRUE;
+}
+
+static const GtkCanvasVec2Class GTK_CANVAS_VEC2_SUM_CLASS =
+{
+  "GtkCanvasVec2Sum",
+  gtk_canvas_vec2_sum_copy,
+  gtk_canvas_vec2_sum_finish,
+  gtk_canvas_vec2_sum_eval,
+};
+
+static void
+gtk_canvas_vec2_sum_copy (GtkCanvasVec2       *vec2,
+                          const GtkCanvasVec2 *source_vec2)
+{
+  GtkCanvasVec2Sum *self = &vec2->sum;
+  const GtkCanvasVec2Sum *source = &source_vec2->sum;
+  gsize i;
+
+  self->class = &GTK_CANVAS_VEC2_SUM_CLASS;
+  self->summands = g_new (GtkCanvasVec2Summand, source->n_summands);
+  self->n_summands = source->n_summands;
+  for (i = 0; i < self->n_summands; i++)
+    {
+      graphene_vec2_init_from_vec2 (&self->summands[i].scale,
+                                    &source->summands[i].scale);
+      gtk_canvas_vec2_init_copy (&self->summands[i].value,
+                                 &source->summands[i].value);
+    }
+
+}
+
+void
+gtk_canvas_vec2_init_sum (GtkCanvasVec2         *vec2,
+                          const graphene_vec2_t *scale,
+                          ...)
+{
+  GtkCanvasVec2Sum *self = &vec2->sum;
+  GArray *array;
+  GtkCanvasVec2Summand summand;
+  va_list args;
+
+  g_assert (scale != NULL);
+
+  self->class = &GTK_CANVAS_VEC2_SUM_CLASS;
+
+  array = g_array_new (FALSE, FALSE, sizeof (GtkCanvasVec2Summand));
+  va_start (args, scale);
+
+  while (scale)
+    {
+      graphene_vec2_init_from_vec2 (&summand.scale, scale);
+      gtk_canvas_vec2_init_copy (&summand.value, va_arg (args, const GtkCanvasVec2 *));
+      g_array_append_val (array, summand);
+      scale = va_arg (args, const graphene_vec2_t *);
+    }
+  va_end (args);
+
+  self->n_summands = array->len;
+  self->summands = (GtkCanvasVec2Summand *) g_array_free (array, FALSE);
+}
+
+/* }}} */
+/* {{{ VARIABLE */
+
+static void
+gtk_canvas_vec2_init_variable_with_variable (GtkCanvasVec2 *vec2,
+                                             GtkCanvasVec2 *variable);
+
+static void
+gtk_canvas_vec2_variable_copy (GtkCanvasVec2       *vec2,
+                               const GtkCanvasVec2 *source_vec2)
+{
+  const GtkCanvasVec2Variable *source = &source_vec2->variable;
+
+  gtk_canvas_vec2_init_variable_with_variable (vec2, g_rc_box_acquire (source->variable));
+}
+
+static void
+gtk_canvas_vec2_variable_finish (GtkCanvasVec2 *vec2)
+{
+  const GtkCanvasVec2Variable *self = &vec2->variable;
+
+  g_rc_box_release (self->variable);
+}
+
+static gboolean
+gtk_canvas_vec2_variable_eval (const GtkCanvasVec2 *vec2,
+                               graphene_vec2_t     *result)
+{
+  const GtkCanvasVec2Variable *self = &vec2->variable;
+
+  return gtk_canvas_vec2_eval (self->variable, result);
+}
+
+static const GtkCanvasVec2Class GTK_CANVAS_VEC2_VARIABLE_CLASS =
+{
+  "GtkCanvasVec2Variable",
+  gtk_canvas_vec2_variable_copy,
+  gtk_canvas_vec2_variable_finish,
+  gtk_canvas_vec2_variable_eval,
+};
+
+static void
+gtk_canvas_vec2_init_variable_with_variable (GtkCanvasVec2 *vec2,
+                                             GtkCanvasVec2 *variable)
+{
+  GtkCanvasVec2Variable *self = &vec2->variable;
+
+  self->class = &GTK_CANVAS_VEC2_VARIABLE_CLASS;
+  
+  self->variable = variable;
+}
+
+void
+gtk_canvas_vec2_init_variable (GtkCanvasVec2 *vec2)
+{
+  GtkCanvasVec2 *variable;
+
+  variable = g_rc_box_new (GtkCanvasVec2);
+  gtk_canvas_vec2_init_invalid (variable);
+
+  gtk_canvas_vec2_init_variable_with_variable (vec2, variable);
+}
+
+GtkCanvasVec2 *
+gtk_canvas_vec2_get_variable (GtkCanvasVec2 *vec2)
+{
+  GtkCanvasVec2Variable *self = &vec2->variable;
+
+  g_return_val_if_fail (self->class == &GTK_CANVAS_VEC2_VARIABLE_CLASS, NULL);
+
+  return self->variable;
+}
+
+/* }}} */
+/* {{{ PUBLIC API */
+
+void
+gtk_canvas_vec2_init_copy (GtkCanvasVec2       *self,
+                           const GtkCanvasVec2 *source)
+{
+  source->class->copy (self, source);
+}
+
+void
+gtk_canvas_vec2_finish (GtkCanvasVec2 *self)
+{
+  self->class->finish (self);
+}
+
+gboolean
+gtk_canvas_vec2_eval (const GtkCanvasVec2 *self,
+                      graphene_vec2_t     *result)
+{
+  g_return_val_if_fail (self != NULL, FALSE);
+  g_return_val_if_fail (result != NULL, FALSE);
+
+  if (self->class->eval (self, result))
+    return TRUE;
+
+  graphene_vec2_init_from_vec2 (result, graphene_vec2_zero ());
+  return FALSE;
+}
+
diff --git a/gtk/gtkcanvasvec2private.h b/gtk/gtkcanvasvec2private.h
new file mode 100644
index 0000000000..b8ad4875b8
--- /dev/null
+++ b/gtk/gtkcanvasvec2private.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2022 Benjamin Otte
+ *
+ * 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.1 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CANVAS_VEC2_PRIVATE_H__
+#define __GTK_CANVAS_VEC2_PRIVATE_H__
+
+#include <glib.h>
+#include <graphene.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCanvasVec2 GtkCanvasVec2;
+typedef struct _GtkCanvasVec2Class GtkCanvasVec2Class;
+typedef struct _GtkCanvasVec2Constant GtkCanvasVec2Constant;
+typedef struct _GtkCanvasVec2Sum GtkCanvasVec2Sum;
+typedef struct _GtkCanvasVec2Summand GtkCanvasVec2Summand;
+typedef struct _GtkCanvasVec2Variable GtkCanvasVec2Variable;
+
+struct _GtkCanvasVec2Constant
+{
+  const GtkCanvasVec2Class *class;
+
+  graphene_vec2_t value;
+};
+
+struct _GtkCanvasVec2Sum
+{
+  const GtkCanvasVec2Class *class;
+  
+  graphene_vec2_t constant;
+
+  gsize n_summands;
+  GtkCanvasVec2Summand *summands;
+};
+
+struct _GtkCanvasVec2Variable
+{
+  const GtkCanvasVec2Class *class;
+
+  /* a GtkRcBox */
+  GtkCanvasVec2 *variable;
+};
+
+struct _GtkCanvasVec2
+{
+  union {
+    const GtkCanvasVec2Class *class;
+    GtkCanvasVec2Constant constant;
+    GtkCanvasVec2Sum sum;
+    GtkCanvasVec2Variable variable;
+  };
+};
+
+struct _GtkCanvasVec2Summand
+{
+  graphene_vec2_t scale;
+  GtkCanvasVec2 value;
+};
+
+
+void                    gtk_canvas_vec2_init_copy               (GtkCanvasVec2          *self,
+                                                                 const GtkCanvasVec2    *source);
+void                    gtk_canvas_vec2_finish                  (GtkCanvasVec2          *self);
+
+gboolean                gtk_canvas_vec2_eval                    (const GtkCanvasVec2    *self,
+                                                                 graphene_vec2_t        *result);
+
+void                    gtk_canvas_vec2_init_invalid            (GtkCanvasVec2          *vec2);
+void                    gtk_canvas_vec2_init_constant           (GtkCanvasVec2          *vec2,
+                                                                 float                   x,
+                                                                 float                   y);
+void                    gtk_canvas_vec2_init_constant_from_vec2 (GtkCanvasVec2          *vec2,
+                                                                 const graphene_vec2_t  *value);
+void                    gtk_canvas_vec2_init_sum                (GtkCanvasVec2          *vec2,
+                                                                 const graphene_vec2_t  *scale,
+                                                                 ...) G_GNUC_NULL_TERMINATED;
+
+void                    gtk_canvas_vec2_init_variable          (GtkCanvasVec2           *vec2);
+GtkCanvasVec2 *         gtk_canvas_vec2_get_variable           (GtkCanvasVec2           *vec2);
+
+G_END_DECLS
+
+#endif /* __GTK_CANVAS_VEC2_PRIVATE_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 63f01bbea8..93db1fb16c 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -32,6 +32,7 @@ gtk_private_sources = files([
   'gtkbuilderprecompile.c',
   'gtkbuiltinicon.c',
   'gtkcellareaboxcontext.c',
+  'gtkcanvasvec2.c',
   'gtkcoloreditor.c',
   'gtkcolorplane.c',
   'gtkcolorpicker.c',


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