[gtk/wip/baedert/transforms6: 1/18] widget: Handle position in transformation matrix



commit 67115a121b86769a94b33ca4cd803a14d7ea9a83
Author: Timm Bäder <mail baedert org>
Date:   Sat Aug 18 07:05:24 2018 +0200

    widget: Handle position in transformation matrix
    
    Most unoptimized version so far.

 gtk/gtksizerequest.c   |  97 +++++++++++++++
 gtk/gtkwidget.c        | 320 ++++++++++++++++++++++---------------------------
 gtk/gtkwidget.h        |   6 +
 gtk/gtkwidgetprivate.h |   7 +-
 4 files changed, 246 insertions(+), 184 deletions(-)
---
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index 197d2413ea..8d3d5e90c8 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -120,6 +120,103 @@ get_box_padding (GtkCssStyle *style,
   border->right = get_number (style, GTK_CSS_PROPERTY_PADDING_RIGHT);
 }
 
+/* translate initial/final into start/end */
+static GtkAlign
+effective_align (GtkAlign         align,
+                 GtkTextDirection direction)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_START:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
+    case GTK_ALIGN_END:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
+    case GTK_ALIGN_FILL:
+    case GTK_ALIGN_CENTER:
+    case GTK_ALIGN_BASELINE:
+    default:
+      return align;
+    }
+}
+
+static void
+adjust_for_align (GtkAlign  align,
+                  gint     *natural_size,
+                  gint     *allocated_pos,
+                  gint     *allocated_size)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_BASELINE:
+    case GTK_ALIGN_FILL:
+    default:
+      /* change nothing */
+      break;
+    case GTK_ALIGN_START:
+      /* keep *allocated_pos where it is */
+      *allocated_size = MIN (*allocated_size, *natural_size);
+      break;
+    case GTK_ALIGN_END:
+      if (*allocated_size > *natural_size)
+        {
+          *allocated_pos += (*allocated_size - *natural_size);
+          *allocated_size = *natural_size;
+        }
+      break;
+    case GTK_ALIGN_CENTER:
+      if (*allocated_size > *natural_size)
+        {
+          *allocated_pos += (*allocated_size - *natural_size) / 2;
+          *allocated_size = MIN (*allocated_size, *natural_size);
+        }
+      break;
+    }
+}
+
+static void
+adjust_for_margin(gint               start_margin,
+                  gint               end_margin,
+                  gint              *minimum_size,
+                  gint              *natural_size,
+                  gint              *allocated_pos,
+                  gint              *allocated_size)
+{
+  *minimum_size -= (start_margin + end_margin);
+  *natural_size -= (start_margin + end_margin);
+  *allocated_pos += start_margin;
+  *allocated_size -= (start_margin + end_margin);
+}
+
+static void
+gtk_widget_adjust_size_allocation (GtkWidget         *widget,
+                                   GtkOrientation     orientation,
+                                   gint              *minimum_size,
+                                   gint              *natural_size,
+                                   gint              *allocated_pos,
+                                   gint              *allocated_size)
+{
+  GtkWidgetPrivate *priv = widget->priv;
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      adjust_for_margin (priv->margin.left,
+                         priv->margin.right,
+                         minimum_size, natural_size,
+                         allocated_pos, allocated_size);
+      adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)),
+                        natural_size, allocated_pos, allocated_size);
+    }
+  else
+    {
+      adjust_for_margin (priv->margin.top,
+                         priv->margin.bottom,
+                         minimum_size, natural_size,
+                         allocated_pos, allocated_size);
+      adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE),
+                        natural_size, allocated_pos, allocated_size);
+    }
+}
+
 static void
 gtk_widget_query_size_for_orientation (GtkWidget        *widget,
                                        GtkOrientation    orientation,
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 0aca366249..18bf5f48d8 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4074,23 +4074,111 @@ void
 gtk_widget_size_allocate (GtkWidget           *widget,
                           const GtkAllocation *allocation,
                           int                  baseline)
+{
+  graphene_matrix_t transform;
+
+  graphene_matrix_init_translate (&transform,
+                                  &GRAPHENE_POINT3D_INIT (allocation->x, allocation->y, 0));
+
+  gtk_widget_size_allocate_transformed (widget,
+                                        allocation->width,
+                                        allocation->height,
+                                        baseline,
+                                        &transform);
+}
+
+/* translate initial/final into start/end */
+static inline GtkAlign
+effective_align (GtkAlign         align,
+                 GtkTextDirection direction)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_START:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
+    case GTK_ALIGN_END:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
+    case GTK_ALIGN_FILL:
+    case GTK_ALIGN_CENTER:
+    case GTK_ALIGN_BASELINE:
+    default:
+      return align;
+    }
+}
+
+static void
+adjust_for_align (GtkAlign           align,
+                  GtkOrientation     orientation,
+                  graphene_matrix_t *transform,
+                  int                nat_size,
+                  int               *allocated_size)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_BASELINE:
+    case GTK_ALIGN_FILL:
+    default:
+      /* change nothing */
+      break;
+    case GTK_ALIGN_START:
+      /* keep *allocated_pos where it is */
+      *allocated_size = MIN (*allocated_size, nat_size);
+      break;
+    case GTK_ALIGN_END:
+      if (*allocated_size > nat_size)
+        {
+          if (orientation == GTK_ORIENTATION_HORIZONTAL)
+            graphene_matrix_translate (transform,
+                                       &GRAPHENE_POINT3D_INIT (*allocated_size - nat_size, 0, 0));
+          else
+            graphene_matrix_translate (transform,
+                                       &GRAPHENE_POINT3D_INIT (0, *allocated_size - nat_size, 0));
+
+          *allocated_size = nat_size;
+        }
+
+      break;
+    case GTK_ALIGN_CENTER:
+      if (*allocated_size > nat_size)
+        {
+          if (orientation == GTK_ORIENTATION_HORIZONTAL)
+            graphene_matrix_translate (transform,
+                                       &GRAPHENE_POINT3D_INIT ((*allocated_size - nat_size) / 2, 0, 0));
+          else
+            graphene_matrix_translate (transform,
+                                       &GRAPHENE_POINT3D_INIT (0, (*allocated_size - nat_size) / 2, 0));
+
+          *allocated_size = MIN (*allocated_size, nat_size);
+        }
+      break;
+    }
+}
+
+void
+gtk_widget_size_allocate_transformed (GtkWidget               *widget,
+                                      int                      width,
+                                      int                      height,
+                                      int                      baseline,
+                                      const graphene_matrix_t *transform)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  graphene_matrix_t final_transform;
   GdkRectangle real_allocation;
   GdkRectangle adjusted_allocation;
   gboolean alloc_needed;
   gboolean size_changed;
   gboolean baseline_changed;
-  gboolean position_changed;
-  gint natural_width, natural_height, dummy = 0;
-  gint min_width, min_height;
+  gboolean transform_changed;
+  int min_width, min_height;
+  int nat_width, nat_height;
   GtkCssStyle *style;
   GtkBorder margin, border, padding;
   GdkDisplay *display;
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (baseline >= -1);
-  g_return_if_fail (allocation != NULL);
+  g_return_if_fail (width >= 0);
+  g_return_if_fail (height >= 0);
 
   gtk_widget_push_verify_invariants (widget);
 
@@ -4111,37 +4199,16 @@ gtk_widget_size_allocate (GtkWidget           *widget,
                  "How does the code know the size to allocate?",
                  gtk_widget_get_name (widget), widget);
     }
-
-  if (GTK_DISPLAY_DEBUG_CHECK (display, GEOMETRY))
-    {
-      gint depth;
-      GtkWidget *parent;
-      const gchar *name;
-
-      depth = 0;
-      parent = widget;
-      while (parent)
-        {
-          depth++;
-          parent = _gtk_widget_get_parent (parent);
-        }
-
-      name = g_type_name (G_OBJECT_TYPE (G_OBJECT (widget)));
-      g_message ("gtk_widget_size_allocate: %*s%s %d %d %d %d, baseline %d",
-                 2 * depth, " ", name,
-                 allocation->x, allocation->y,
-                 allocation->width, allocation->height,
-                 baseline);
-    }
 #endif /* G_ENABLE_DEBUG */
 
   alloc_needed = priv->alloc_needed;
   /* Preserve request/allocate ordering */
   priv->alloc_needed = FALSE;
 
-  real_allocation = *allocation;
+  real_allocation = (GtkAllocation) {0, 0, width, height};
 
-  priv->allocated_size = *allocation;
+  priv->allocated_transform = *transform;
+  priv->allocated_size = real_allocation;
   priv->allocated_size_baseline = baseline;
 
   adjusted_allocation = real_allocation;
@@ -4152,9 +4219,9 @@ gtk_widget_size_allocate (GtkWidget           *widget,
        * when aligning implicitly.
        */
       gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
-                          &min_width, &natural_width, NULL, NULL);
+                          &min_width, &nat_width, NULL, NULL);
       gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, real_allocation.width,
-                          &min_height, &natural_height, NULL, NULL);
+                          &min_height, &nat_height, NULL, NULL);
     }
   else
     {
@@ -4163,9 +4230,9 @@ gtk_widget_size_allocate (GtkWidget           *widget,
        * when aligning implicitly.
        */
       gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1,
-                          &min_height, &natural_height, NULL, NULL);
+                          &min_height, &nat_height, NULL, NULL);
       gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, real_allocation.height,
-                          &min_width, &natural_width, NULL, NULL);
+                          &min_width, &nat_width, NULL, NULL);
     }
 
 #ifdef G_ENABLE_CONSISTENCY_CHECKS
@@ -4178,40 +4245,33 @@ gtk_widget_size_allocate (GtkWidget           *widget,
                real_allocation.width, real_allocation.height,
                min_width, min_height);
 #endif
-  /* Now that we have the right natural height and width, go ahead and remove any margins from the
-   * allocated sizes and possibly limit them to the natural sizes */
-  gtk_widget_adjust_size_allocation (widget,
-                                     GTK_ORIENTATION_HORIZONTAL,
-                                     &dummy,
-                                     &natural_width,
-                                     &adjusted_allocation.x,
-                                     &adjusted_allocation.width);
-  gtk_widget_adjust_size_allocation (widget,
-                                     GTK_ORIENTATION_VERTICAL,
-                                     &dummy,
-                                     &natural_height,
-                                     &adjusted_allocation.y,
-                                     &adjusted_allocation.height);
+
+  final_transform = *transform;
+  /* Remove widget margins from the allocated size */
+  graphene_matrix_translate (&final_transform,
+                             &GRAPHENE_POINT3D_INIT (priv->margin.left,
+                                                     priv->margin.top, 0));
+  adjusted_allocation.width  -= priv->margin.left + priv->margin.right;
+  adjusted_allocation.height -= priv->margin.top  + priv->margin.bottom;
+
+  nat_width -= priv->margin.left + priv->margin.right;
+  nat_height -= priv->margin.top + priv->margin.bottom;
+
+  adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)),
+                    GTK_ORIENTATION_HORIZONTAL,
+                    &final_transform,
+                    nat_width,
+                    &adjusted_allocation.width);
+  adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE),
+                    GTK_ORIENTATION_VERTICAL,
+                    &final_transform,
+                    nat_height,
+                    &adjusted_allocation.height);
+
   if (baseline >= 0)
     baseline -= priv->margin.top;
 
-  if (adjusted_allocation.x < real_allocation.x ||
-      adjusted_allocation.y < real_allocation.y ||
-      (adjusted_allocation.x + adjusted_allocation.width) >
-      (real_allocation.x + real_allocation.width) ||
-      (adjusted_allocation.y + adjusted_allocation.height >
-       real_allocation.y + real_allocation.height))
-    {
-      g_warning ("%s %p attempted to adjust its size allocation from %d,%d %dx%d to %d,%d %dx%d. 
adjust_size_allocation must keep allocation inside original bounds",
-                 G_OBJECT_TYPE_NAME (widget), widget,
-                 real_allocation.x, real_allocation.y, real_allocation.width, real_allocation.height,
-                 adjusted_allocation.x, adjusted_allocation.y, adjusted_allocation.width, 
adjusted_allocation.height);
-    }
-  else
-    {
-      real_allocation = adjusted_allocation;
-    }
-
+  real_allocation = adjusted_allocation;
   if (real_allocation.width < 0 || real_allocation.height < 0)
     {
       g_warning ("gtk_widget_size_allocate(): attempt to allocate %s %s %p with width %d and height %d",
@@ -4232,12 +4292,14 @@ gtk_widget_size_allocate (GtkWidget           *widget,
   baseline_changed = priv->allocated_baseline != baseline;
   size_changed = (priv->allocation.width != real_allocation.width ||
                   priv->allocation.height != real_allocation.height);
-  position_changed = (priv->allocation.x != real_allocation.x ||
-                      priv->allocation.y != real_allocation.y);
+  transform_changed = memcmp (&final_transform,
+                              &priv->transform,
+                              sizeof (graphene_matrix_t)) != 0;
 
   /* Set the widget allocation to real_allocation now, pass the smaller allocation to the vfunc */
   priv->allocation = real_allocation;
   priv->allocated_baseline = baseline;
+  priv->transform = final_transform;
 
   if (!alloc_needed && !size_changed && !baseline_changed)
     {
@@ -4302,7 +4364,7 @@ gtk_widget_size_allocate (GtkWidget           *widget,
 check_clip:
   if (size_changed || baseline_changed)
     gtk_widget_queue_draw (widget);
-  else if (position_changed && priv->parent)
+  else if (transform_changed && priv->parent)
     gtk_widget_queue_draw (priv->parent);
 
 out:
@@ -4564,103 +4626,6 @@ gtk_widget_real_size_allocate (GtkWidget *widget,
      }
 }
 
-/* translate initial/final into start/end */
-static GtkAlign
-effective_align (GtkAlign         align,
-                 GtkTextDirection direction)
-{
-  switch (align)
-    {
-    case GTK_ALIGN_START:
-      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
-    case GTK_ALIGN_END:
-      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
-    case GTK_ALIGN_FILL:
-    case GTK_ALIGN_CENTER:
-    case GTK_ALIGN_BASELINE:
-    default:
-      return align;
-    }
-}
-
-static void
-adjust_for_align (GtkAlign  align,
-                  gint     *natural_size,
-                  gint     *allocated_pos,
-                  gint     *allocated_size)
-{
-  switch (align)
-    {
-    case GTK_ALIGN_BASELINE:
-    case GTK_ALIGN_FILL:
-    default:
-      /* change nothing */
-      break;
-    case GTK_ALIGN_START:
-      /* keep *allocated_pos where it is */
-      *allocated_size = MIN (*allocated_size, *natural_size);
-      break;
-    case GTK_ALIGN_END:
-      if (*allocated_size > *natural_size)
-       {
-         *allocated_pos += (*allocated_size - *natural_size);
-         *allocated_size = *natural_size;
-       }
-      break;
-    case GTK_ALIGN_CENTER:
-      if (*allocated_size > *natural_size)
-       {
-         *allocated_pos += (*allocated_size - *natural_size) / 2;
-         *allocated_size = MIN (*allocated_size, *natural_size);
-       }
-      break;
-    }
-}
-
-static void
-adjust_for_margin(gint               start_margin,
-                  gint               end_margin,
-                  gint              *minimum_size,
-                  gint              *natural_size,
-                  gint              *allocated_pos,
-                  gint              *allocated_size)
-{
-  *minimum_size -= (start_margin + end_margin);
-  *natural_size -= (start_margin + end_margin);
-  *allocated_pos += start_margin;
-  *allocated_size -= (start_margin + end_margin);
-}
-
-void
-gtk_widget_adjust_size_allocation (GtkWidget         *widget,
-                                   GtkOrientation     orientation,
-                                   gint              *minimum_size,
-                                   gint              *natural_size,
-                                   gint              *allocated_pos,
-                                   gint              *allocated_size)
-{
-  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      adjust_for_margin (priv->margin.left,
-                         priv->margin.right,
-                         minimum_size, natural_size,
-                         allocated_pos, allocated_size);
-      adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)),
-                        natural_size, allocated_pos, allocated_size);
-    }
-  else
-    {
-      adjust_for_margin (priv->margin.top,
-                         priv->margin.bottom,
-                         minimum_size, natural_size,
-                         allocated_pos, allocated_size);
-      adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE),
-                        natural_size, allocated_pos, allocated_size);
-    }
-}
-
 static gboolean
 gtk_widget_real_can_activate_accel (GtkWidget *widget,
                                     guint      signal_id)
@@ -11138,7 +11103,12 @@ gtk_widget_get_allocated_size (GtkWidget     *widget,
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (allocation != NULL);
 
-  *allocation = priv->allocated_size;
+  *allocation = (GtkAllocation) {
+    (int)graphene_matrix_get_value (&priv->allocated_transform, 3, 0),
+    (int)graphene_matrix_get_value (&priv->allocated_transform, 3, 1),
+    priv->allocated_size.width,
+    priv->allocated_size.height
+  };
 
   if (baseline)
     *baseline = priv->allocated_size_baseline;
@@ -11172,7 +11142,12 @@ gtk_widget_get_allocation (GtkWidget     *widget,
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (allocation != NULL);
 
-  *allocation = priv->allocation;
+  *allocation = (GtkAllocation) {
+    (int)graphene_matrix_get_value (&priv->transform, 0, 3),
+    (int)graphene_matrix_get_value (&priv->transform, 1, 3),
+    priv->allocation.width,
+    priv->allocation.height
+  };
 }
 
 /**
@@ -13040,7 +13015,6 @@ gtk_widget_create_render_node (GtkWidget   *widget,
 {
   GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
-  const gboolean needs_transform = !graphene_matrix_is_identity (&priv->transform);
   GtkCssValue *filter_value;
   double opacity;
   GtkCssStyle *style;
@@ -13060,9 +13034,6 @@ gtk_widget_create_render_node (GtkWidget   *widget,
                            G_OBJECT_TYPE_NAME (widget), widget,
                            allocation.width, allocation.height);
 
-  if (needs_transform)
-    gtk_snapshot_push_transform (snapshot, &priv->transform);
-
   filter_value = _gtk_style_context_peek_property (_gtk_widget_get_style_context (widget), 
GTK_CSS_PROPERTY_FILTER);
   gtk_css_filter_value_push_snapshot (filter_value, snapshot);
 
@@ -13108,9 +13079,6 @@ gtk_widget_create_render_node (GtkWidget   *widget,
   gtk_widget_maybe_add_debug_render_nodes (widget, snapshot);
 #endif
 
-  if (needs_transform)
-    gtk_snapshot_pop (snapshot);
-
   gtk_snapshot_pop (snapshot); /* Debug */
 
   return gtk_snapshot_free_to_node (snapshot);
@@ -13484,17 +13452,13 @@ gtk_widget_snapshot_child (GtkWidget   *widget,
                            GtkSnapshot *snapshot)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child);
-  int x, y;
 
   g_return_if_fail (_gtk_widget_get_parent (child) == widget);
   g_return_if_fail (snapshot != NULL);
 
-  x = priv->allocation.x;
-  y = priv->allocation.y;
-
-  gtk_snapshot_offset (snapshot, x, y);
+  gtk_snapshot_push_transform (snapshot, &priv->transform);
   gtk_widget_snapshot (child, snapshot);
-  gtk_snapshot_offset (snapshot, -x, -y);
+  gtk_snapshot_pop (snapshot);
 }
 
 /**
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 01d7327116..580da9865b 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -408,6 +408,12 @@ GDK_AVAILABLE_IN_ALL
 void       gtk_widget_size_allocate       (GtkWidget           *widget,
                                            const GtkAllocation *allocation,
                                            int                  baseline);
+GDK_AVAILABLE_IN_ALL
+void       gtk_widget_size_allocate_transformed (GtkWidget               *widget,
+                                                 int                      width,
+                                                 int                      height,
+                                                 int                      baseline,
+                                                 const graphene_matrix_t *transform);
 
 GDK_AVAILABLE_IN_ALL
 GtkSizeRequestMode  gtk_widget_get_request_mode               (GtkWidget      *widget);
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 69622e9821..ec45b27205 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -143,6 +143,7 @@ struct _GtkWidgetPrivate
   GtkAllocation allocation;
   gint allocated_baseline;
 
+  graphene_matrix_t allocated_transform;
   graphene_matrix_t transform;
 
   /* The widget's requested sizes */
@@ -293,12 +294,6 @@ void              gtk_widget_adjust_size_request           (GtkWidget      *widg
                                                             GtkOrientation  orientation,
                                                             gint           *minimum_size,
                                                             gint           *natural_size);
-void              gtk_widget_adjust_size_allocation        (GtkWidget         *widget,
-                                                            GtkOrientation     orientation,
-                                                            gint              *minimum_size,
-                                                            gint              *natural_size,
-                                                            gint              *allocated_pos,
-                                                            gint              *allocated_size);
 void              gtk_widget_adjust_baseline_request       (GtkWidget *widget,
                                                             gint      *minimum_baseline,
                                                             gint      *natural_baseline);


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