[gtk/wip/otte/boxes: 49/52] cssboxes: Introduce



commit 19ffb40b27e372bcbdd3847749248c0282159b0c
Author: Benjamin Otte <otte redhat com>
Date:   Fri Feb 15 02:57:46 2019 +0100

    cssboxes: Introduce
    
    Split out the code for computing CSS boxes from given variables from the
    background render code. This way, it can be shared between different
    codebases.
    
    Also, make that code completely be contained of static inline functions.
    That ensures that it can be 100% inlined in cases where only parts of
    the rectangle are needed (like in gtk_widget_get_width() in the future).
    
    This will require some more patches to actually work, but those will
    follow.

 gtk/gtkcssboxesimplprivate.h | 493 +++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkcssboxesprivate.h     |  91 ++++++++
 gtk/gtkrenderbackground.c    |  94 ++++-----
 3 files changed, 621 insertions(+), 57 deletions(-)
---
diff --git a/gtk/gtkcssboxesimplprivate.h b/gtk/gtkcssboxesimplprivate.h
new file mode 100644
index 0000000000..0cab9750c5
--- /dev/null
+++ b/gtk/gtkcssboxesimplprivate.h
@@ -0,0 +1,493 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2019 Benjamin Otte <otte gnome org>
+ *
+ * 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/>.
+ */
+
+#ifndef __GTK_CSS_BOXES_IMPL_PRIVATE_H__
+#define __GTK_CSS_BOXES_IMPL_PRIVATE_H__
+
+#include "gtkcssboxesprivate.h"
+
+#include "gtkcsscornervalueprivate.h"
+#include "gtkcssnodeprivate.h"
+#include "gtkcssnumbervalueprivate.h"
+#include "gtkwidgetprivate.h"
+
+/* This file is included from gtkcssboxesprivate.h */
+
+static inline void
+gtk_css_boxes_init (GtkCssBoxes *boxes,
+                    GtkWidget   *widget)
+{
+  gtk_css_boxes_init_content_box (boxes,
+                                  gtk_css_node_get_style (widget->priv->cssnode),
+                                  0, 0,
+                                  gtk_widget_get_width (widget),
+                                  gtk_widget_get_height (widget));
+}
+
+static inline void
+gtk_css_boxes_init_content_box (GtkCssBoxes *boxes,
+                                GtkCssStyle *style,
+                                double       x,
+                                double       y,
+                                double       width,
+                                double       height)
+{
+  memset (boxes, 0, sizeof (GtkCssBoxes));
+
+  boxes->style = style;
+  boxes->box[GTK_CSS_AREA_CONTENT_BOX].bounds = GRAPHENE_RECT_INIT (x, y, width, height);
+  boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_init_border_box (GtkCssBoxes *boxes,
+                               GtkCssStyle *style,
+                               double       x,
+                               double       y,
+                               double       width,
+                               double       height)
+{
+  memset (boxes, 0, sizeof (GtkCssBoxes));
+
+  boxes->style = style;
+  boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds = GRAPHENE_RECT_INIT (x, y, width, height);
+  boxes->has_rect[GTK_CSS_AREA_BORDER_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_rect_grow (GskRoundedRect *dest,
+                         GskRoundedRect *src,
+                         GtkCssStyle    *style,
+                         int             top_property,
+                         int             right_property,
+                         int             bottom_property,
+                         int             left_property)
+{
+  double top = _gtk_css_number_value_get (gtk_css_style_get_value (style, top_property), 100);
+  double right = _gtk_css_number_value_get (gtk_css_style_get_value (style, right_property), 100);
+  double bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, bottom_property), 100);
+  double left = _gtk_css_number_value_get (gtk_css_style_get_value (style, left_property), 100);
+
+  dest->bounds.origin.x = src->bounds.origin.x - left;
+  dest->bounds.origin.y = src->bounds.origin.y - top;
+  dest->bounds.size.width = src->bounds.size.width + left + right;
+  dest->bounds.size.height = src->bounds.size.height + top + bottom;
+}
+
+static inline void
+gtk_css_boxes_rect_shrink (GskRoundedRect *dest,
+                           GskRoundedRect *src,
+                           GtkCssStyle    *style,
+                           int             top_property,
+                           int             right_property,
+                           int             bottom_property,
+                           int             left_property)
+{
+  double top = _gtk_css_number_value_get (gtk_css_style_get_value (style, top_property), 100);
+  double right = _gtk_css_number_value_get (gtk_css_style_get_value (style, right_property), 100);
+  double bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, bottom_property), 100);
+  double left = _gtk_css_number_value_get (gtk_css_style_get_value (style, left_property), 100);
+
+  /* FIXME: Do we need underflow checks here? */
+  dest->bounds.origin.x = src->bounds.origin.x + left;
+  dest->bounds.origin.y = src->bounds.origin.y + top;
+  dest->bounds.size.width = src->bounds.size.width - left - right;
+  dest->bounds.size.height = src->bounds.size.height - top - bottom;
+}
+
+static inline void gtk_css_boxes_compute_padding_rect (GtkCssBoxes *boxes);
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_rect (GtkCssBoxes *boxes,
+                        GtkCssArea   area)
+{
+  switch (area)
+    {
+      case GTK_CSS_AREA_BORDER_BOX:
+        return gtk_css_boxes_get_border_rect (boxes);
+      case GTK_CSS_AREA_PADDING_BOX:
+        return gtk_css_boxes_get_padding_rect (boxes);
+      case GTK_CSS_AREA_CONTENT_BOX:
+        return gtk_css_boxes_get_content_rect (boxes);
+      default:
+        g_assert_not_reached ();
+        return NULL;
+    }
+}
+
+static inline void
+gtk_css_boxes_compute_border_rect (GtkCssBoxes *boxes)
+{
+  if (boxes->has_rect[GTK_CSS_AREA_BORDER_BOX])
+    return;
+
+  gtk_css_boxes_compute_padding_rect (boxes);
+
+  gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_BORDER_BOX],
+                           &boxes->box[GTK_CSS_AREA_PADDING_BOX],
+                           boxes->style,
+                           GTK_CSS_PROPERTY_BORDER_TOP_WIDTH,
+                           GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+                           GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+                           GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH);
+
+  boxes->has_rect[GTK_CSS_AREA_BORDER_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_padding_rect (GtkCssBoxes *boxes)
+{
+  if (boxes->has_rect[GTK_CSS_AREA_PADDING_BOX])
+    return;
+
+  if (boxes->has_rect[GTK_CSS_AREA_BORDER_BOX])
+    {
+      gtk_css_boxes_rect_shrink (&boxes->box[GTK_CSS_AREA_PADDING_BOX],
+                                 &boxes->box[GTK_CSS_AREA_BORDER_BOX],
+                                 boxes->style,
+                                 GTK_CSS_PROPERTY_BORDER_TOP_WIDTH,
+                                 GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+                                 GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+                                 GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH);
+    }
+  else
+    {
+      gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_PADDING_BOX],
+                               &boxes->box[GTK_CSS_AREA_CONTENT_BOX],
+                               boxes->style,
+                               GTK_CSS_PROPERTY_PADDING_TOP,
+                               GTK_CSS_PROPERTY_PADDING_RIGHT,
+                               GTK_CSS_PROPERTY_PADDING_BOTTOM,
+                               GTK_CSS_PROPERTY_PADDING_LEFT);
+    }
+
+  boxes->has_rect[GTK_CSS_AREA_PADDING_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_content_rect (GtkCssBoxes *boxes)
+{
+  if (boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX])
+    return;
+
+  gtk_css_boxes_compute_padding_rect (boxes);
+
+  gtk_css_boxes_rect_shrink (&boxes->box[GTK_CSS_AREA_CONTENT_BOX],
+                             &boxes->box[GTK_CSS_AREA_PADDING_BOX],
+                             boxes->style,
+                             GTK_CSS_PROPERTY_PADDING_TOP,
+                             GTK_CSS_PROPERTY_PADDING_RIGHT,
+                             GTK_CSS_PROPERTY_PADDING_BOTTOM,
+                             GTK_CSS_PROPERTY_PADDING_LEFT);
+
+  boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_margin_rect (GtkCssBoxes *boxes)
+{
+  if (boxes->has_rect[GTK_CSS_AREA_MARGIN_BOX])
+    return;
+
+  gtk_css_boxes_compute_border_rect (boxes);
+
+  gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_MARGIN_BOX],
+                           &boxes->box[GTK_CSS_AREA_BORDER_BOX],
+                           boxes->style,
+                           GTK_CSS_PROPERTY_MARGIN_TOP,
+                           GTK_CSS_PROPERTY_MARGIN_RIGHT,
+                           GTK_CSS_PROPERTY_MARGIN_BOTTOM,
+                           GTK_CSS_PROPERTY_MARGIN_LEFT);
+
+  boxes->has_rect[GTK_CSS_AREA_MARGIN_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_outline_rect (GtkCssBoxes *boxes)
+{
+  graphene_rect_t *dest, *src;
+  double d;
+
+  if (boxes->has_rect[GTK_CSS_AREA_OUTLINE_BOX])
+    return;
+
+  gtk_css_boxes_compute_border_rect (boxes);
+
+  dest = &boxes->box[GTK_CSS_AREA_OUTLINE_BOX].bounds;
+  src = &boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds;
+
+  d = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 
100) +
+      _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 
100);
+
+  dest->origin.x = src->origin.x - d;
+  dest->origin.y = src->origin.y - d;
+  dest->size.width = src->size.width + d + d;
+  dest->size.height = src->size.height + d + d;
+
+  boxes->has_rect[GTK_CSS_AREA_OUTLINE_BOX] = TRUE;
+}
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_margin_rect (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_margin_rect (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_MARGIN_BOX].bounds;
+}
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_border_rect (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_border_rect (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds;
+}
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_padding_rect (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_padding_rect (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_PADDING_BOX].bounds;
+}
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_content_rect (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_content_rect (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_CONTENT_BOX].bounds;
+}
+
+static inline const graphene_rect_t *
+gtk_css_boxes_get_outline_rect (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_outline_rect (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_OUTLINE_BOX].bounds;
+}
+
+/* clamp border radius, following CSS specs */
+static inline void
+gtk_css_boxes_clamp_border_radius (GskRoundedRect *box)
+{
+  gdouble factor = 1.0;
+  gdouble corners;
+
+  corners = box->corner[GSK_CORNER_TOP_LEFT].width + box->corner[GSK_CORNER_TOP_RIGHT].width;
+  if (corners != 0)
+    factor = MIN (factor, box->bounds.size.width / corners);
+
+  corners = box->corner[GSK_CORNER_TOP_RIGHT].height + box->corner[GSK_CORNER_BOTTOM_RIGHT].height;
+  if (corners != 0)
+    factor = MIN (factor, box->bounds.size.height / corners);
+
+  corners = box->corner[GSK_CORNER_BOTTOM_RIGHT].width + box->corner[GSK_CORNER_BOTTOM_LEFT].width;
+  if (corners != 0)
+    factor = MIN (factor, box->bounds.size.width / corners);
+
+  corners = box->corner[GSK_CORNER_TOP_LEFT].height + box->corner[GSK_CORNER_BOTTOM_LEFT].height;
+  if (corners != 0)
+    factor = MIN (factor, box->bounds.size.height / corners);
+
+  box->corner[GSK_CORNER_TOP_LEFT].width *= factor;
+  box->corner[GSK_CORNER_TOP_LEFT].height *= factor;
+  box->corner[GSK_CORNER_TOP_RIGHT].width *= factor;
+  box->corner[GSK_CORNER_TOP_RIGHT].height *= factor;
+  box->corner[GSK_CORNER_BOTTOM_RIGHT].width *= factor;
+  box->corner[GSK_CORNER_BOTTOM_RIGHT].height *= factor;
+  box->corner[GSK_CORNER_BOTTOM_LEFT].width *= factor;
+  box->corner[GSK_CORNER_BOTTOM_LEFT].height *= factor;
+}
+
+static inline void
+gtk_css_boxes_apply_border_radius (GskRoundedRect    *box,
+                                   const GtkCssValue *top_left,
+                                   const GtkCssValue *top_right,
+                                   const GtkCssValue *bottom_right,
+                                   const GtkCssValue *bottom_left)
+{
+  box->corner[GSK_CORNER_TOP_LEFT].width = _gtk_css_corner_value_get_x (top_left, box->bounds.size.width);
+  box->corner[GSK_CORNER_TOP_LEFT].height = _gtk_css_corner_value_get_y (top_left, box->bounds.size.height);
+
+  box->corner[GSK_CORNER_TOP_RIGHT].width = _gtk_css_corner_value_get_x (top_right, box->bounds.size.width);
+  box->corner[GSK_CORNER_TOP_RIGHT].height = _gtk_css_corner_value_get_y (top_right, 
box->bounds.size.height);
+
+  box->corner[GSK_CORNER_BOTTOM_RIGHT].width = _gtk_css_corner_value_get_x (bottom_right, 
box->bounds.size.width);
+  box->corner[GSK_CORNER_BOTTOM_RIGHT].height = _gtk_css_corner_value_get_y (bottom_right, 
box->bounds.size.height);
+
+  box->corner[GSK_CORNER_BOTTOM_LEFT].width = _gtk_css_corner_value_get_x (bottom_left, 
box->bounds.size.width);
+  box->corner[GSK_CORNER_BOTTOM_LEFT].height = _gtk_css_corner_value_get_y (bottom_left, 
box->bounds.size.height);
+
+  gtk_css_boxes_clamp_border_radius (box);
+}
+
+/* NB: width and height must be >= 0 */
+static inline void
+gtk_css_boxes_shrink_border_radius (graphene_size_t       *dest,
+                                    const graphene_size_t *src,
+                                    double                 width,
+                                    double                 height)
+{
+  dest->width = src->width - width;
+  dest->height = src->height - height;
+
+  if (dest->width <= 0 || dest->height <= 0)
+    {
+      dest->width = 0;
+      dest->height = 0;
+    }
+}
+
+static inline void
+gtk_css_boxes_shrink_corners (GskRoundedRect       *dest,
+                              const GskRoundedRect *src)
+{
+  double top = dest->bounds.origin.y - src->bounds.origin.y;
+  double right = src->bounds.origin.x + src->bounds.size.width - dest->bounds.origin.x - 
dest->bounds.size.width;
+  double bottom = src->bounds.origin.y + src->bounds.size.height - dest->bounds.origin.y - 
dest->bounds.size.height;
+  double left = dest->bounds.origin.x - src->bounds.origin.x;
+
+  gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_TOP_LEFT],
+                                      &src->corner[GSK_CORNER_TOP_LEFT],
+                                      top, left);
+  gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_TOP_RIGHT],
+                                      &src->corner[GSK_CORNER_TOP_RIGHT],
+                                      top, right);
+  gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_BOTTOM_RIGHT],
+                                      &src->corner[GSK_CORNER_BOTTOM_RIGHT],
+                                      bottom, right);
+  gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_BOTTOM_LEFT],
+                                      &src->corner[GSK_CORNER_BOTTOM_LEFT],
+                                      bottom, left);
+}
+
+static inline void
+gtk_css_boxes_compute_border_box (GtkCssBoxes *boxes)
+{
+  if (boxes->has_box[GTK_CSS_AREA_BORDER_BOX])
+    return;
+
+  gtk_css_boxes_compute_border_rect (boxes);
+
+  gtk_css_boxes_apply_border_radius (&boxes->box[GTK_CSS_AREA_BORDER_BOX],
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS));
+
+  boxes->has_box[GTK_CSS_AREA_BORDER_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_padding_box (GtkCssBoxes *boxes)
+{
+  if (boxes->has_box[GTK_CSS_AREA_PADDING_BOX])
+    return;
+
+  gtk_css_boxes_compute_border_box (boxes);
+  gtk_css_boxes_compute_padding_rect (boxes);
+
+  gtk_css_boxes_shrink_corners (&boxes->box[GTK_CSS_AREA_PADDING_BOX],
+                                &boxes->box[GTK_CSS_AREA_BORDER_BOX]);
+
+  boxes->has_box[GTK_CSS_AREA_PADDING_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_content_box (GtkCssBoxes *boxes)
+{
+  if (boxes->has_box[GTK_CSS_AREA_CONTENT_BOX])
+    return;
+
+  gtk_css_boxes_compute_padding_box (boxes);
+  gtk_css_boxes_compute_content_rect (boxes);
+
+  gtk_css_boxes_shrink_corners (&boxes->box[GTK_CSS_AREA_CONTENT_BOX],
+                                &boxes->box[GTK_CSS_AREA_PADDING_BOX]);
+
+  boxes->has_box[GTK_CSS_AREA_CONTENT_BOX] = TRUE;
+}
+
+static inline void
+gtk_css_boxes_compute_outline_box (GtkCssBoxes *boxes)
+{
+  if (boxes->has_box[GTK_CSS_AREA_OUTLINE_BOX])
+    return;
+
+  gtk_css_boxes_compute_outline_rect (boxes);
+
+  gtk_css_boxes_apply_border_radius (&boxes->box[GTK_CSS_AREA_OUTLINE_BOX],
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_OUTLINE_TOP_LEFT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_OUTLINE_TOP_RIGHT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_OUTLINE_BOTTOM_RIGHT_RADIUS),
+                                     gtk_css_style_get_value (boxes->style, 
GTK_CSS_PROPERTY_OUTLINE_BOTTOM_LEFT_RADIUS));
+
+  boxes->has_box[GTK_CSS_AREA_OUTLINE_BOX] = TRUE;
+}
+
+static inline const GskRoundedRect *
+gtk_css_boxes_get_box (GtkCssBoxes *boxes,
+                       GtkCssArea  area)
+{
+  switch (area)
+    {
+      case GTK_CSS_AREA_BORDER_BOX:
+        return gtk_css_boxes_get_border_box (boxes);
+      case GTK_CSS_AREA_PADDING_BOX:
+        return gtk_css_boxes_get_padding_box (boxes);
+      case GTK_CSS_AREA_CONTENT_BOX:
+        return gtk_css_boxes_get_content_box (boxes);
+      default:
+        g_assert_not_reached ();
+        return NULL;
+    }
+}
+
+static inline const GskRoundedRect *
+gtk_css_boxes_get_border_box (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_border_box (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_BORDER_BOX];
+}
+
+static inline const GskRoundedRect *
+gtk_css_boxes_get_padding_box (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_padding_box (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_PADDING_BOX];
+}
+
+static inline const GskRoundedRect *
+gtk_css_boxes_get_content_box (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_content_box (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_CONTENT_BOX];
+}
+
+static inline const GskRoundedRect *
+gtk_css_boxes_get_outline_box (GtkCssBoxes *boxes)
+{
+  gtk_css_boxes_compute_outline_box (boxes);
+
+  return &boxes->box[GTK_CSS_AREA_OUTLINE_BOX];
+}
+
+#endif /* __GTK_CSS_BOXES_IMPL_PRIVATE_H__ */
diff --git a/gtk/gtkcssboxesprivate.h b/gtk/gtkcssboxesprivate.h
new file mode 100644
index 0000000000..d90ba1e598
--- /dev/null
+++ b/gtk/gtkcssboxesprivate.h
@@ -0,0 +1,91 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2019 Benjamin Otte <otte gnome org>
+ *
+ * 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/>.
+ */
+
+#ifndef __GTK_CSS_BOXES_PRIVATE_H__
+#define __GTK_CSS_BOXES_PRIVATE_H__
+
+#include "gtkcsstypesprivate.h"
+
+G_BEGIN_DECLS
+
+/*
+ * The idea behind this file is that it provides an on-stack representation
+ * for all the CSS boxes one can have to deal with in the CSS box model so that
+ * higher level code can use convenient and readable function calls instead of
+ * doing complicated math.
+ *
+ * However, because computing all those rectangles is prohibitively expensive,
+ * this struct does it lazily.
+ * And then we inline all the code, so that whenever we use this struct, the
+ * compiler can optimize out the parts we don't need in that particular use
+ * case.
+ */
+
+typedef struct _GtkCssBoxes GtkCssBoxes;
+
+/* ahem... 
+ * Let's extend GtkCssArea a bit here. */
+#define GTK_CSS_AREA_MARGIN_BOX (3)
+#define GTK_CSS_AREA_OUTLINE_BOX (4)
+#define GTK_CSS_AREA_N_BOXES (5)
+
+
+struct _GtkCssBoxes
+{
+  GtkCssStyle *style;
+  GskRoundedRect box[GTK_CSS_AREA_N_BOXES];
+  gboolean has_rect[GTK_CSS_AREA_N_BOXES]; /* TRUE if we have initialized just the bounds rect */
+  gboolean has_box[GTK_CSS_AREA_N_BOXES]; /* TRUE if we have initialized the whole box */
+};
+
+static inline void                      gtk_css_boxes_init                      (GtkCssBoxes      *boxes,
+                                                                                 GtkWidget        *widget);
+static inline void                      gtk_css_boxes_init_content_box          (GtkCssBoxes      *boxes,
+                                                                                 GtkCssStyle      *style,
+                                                                                 double            x,
+                                                                                 double            y,
+                                                                                 double            width,
+                                                                                 double            height);
+static inline void                      gtk_css_boxes_init_border_box           (GtkCssBoxes      *boxes,
+                                                                                 GtkCssStyle      *style,
+                                                                                 double            x,
+                                                                                 double            y,
+                                                                                 double            width,
+                                                                                 double            height);
+
+static inline const graphene_rect_t *   gtk_css_boxes_get_rect                  (GtkCssBoxes      *boxes,
+                                                                                 GtkCssArea        area);
+static inline const graphene_rect_t *   gtk_css_boxes_get_margin_rect           (GtkCssBoxes      *boxes);
+static inline const graphene_rect_t *   gtk_css_boxes_get_border_rect           (GtkCssBoxes      *boxes);
+static inline const graphene_rect_t *   gtk_css_boxes_get_padding_rect          (GtkCssBoxes      *boxes);
+static inline const graphene_rect_t *   gtk_css_boxes_get_content_rect          (GtkCssBoxes      *boxes);
+static inline const graphene_rect_t *   gtk_css_boxes_get_outline_rect          (GtkCssBoxes      *boxes);
+
+static inline const GskRoundedRect *    gtk_css_boxes_get_box                   (GtkCssBoxes      *boxes,
+                                                                                 GtkCssArea        area);
+static inline const GskRoundedRect *    gtk_css_boxes_get_border_box            (GtkCssBoxes      *boxes);
+static inline const GskRoundedRect *    gtk_css_boxes_get_padding_box           (GtkCssBoxes      *boxes);
+static inline const GskRoundedRect *    gtk_css_boxes_get_content_box           (GtkCssBoxes      *boxes);
+static inline const GskRoundedRect *    gtk_css_boxes_get_outline_box           (GtkCssBoxes      *boxes);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_BOXES_PRIVATE_H__ */
+
+/* and finally include the actual code for the functions */
+#include "gtkcssboxesimplprivate.h"
+
diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c
index 0be739f679..b18e14d516 100644
--- a/gtk/gtkrenderbackground.c
+++ b/gtk/gtkrenderbackground.c
@@ -25,6 +25,7 @@
 
 #include "gtkcssarrayvalueprivate.h"
 #include "gtkcssbgsizevalueprivate.h"
+#include "gtkcssboxesprivate.h"
 #include "gtkcsscornervalueprivate.h"
 #include "gtkcssenumvalueprivate.h"
 #include "gtkcssimagevalueprivate.h"
@@ -47,49 +48,43 @@
  */
 #include "fallback-c89.c"
 
-typedef struct _GtkThemingBackground GtkThemingBackground;
-
-#define N_BOXES (3)
-
-struct _GtkThemingBackground {
-  GtkCssStyle *style;
-
-  GskRoundedRect boxes[N_BOXES];
-};
-
 static void
-gtk_theming_background_snapshot_color (const GtkThemingBackground *bg,
-                                       GtkSnapshot                *snapshot,
-                                       const GdkRGBA              *bg_color,
-                                       const GtkCssValue          *background_image)
+gtk_theming_background_snapshot_color (GtkCssBoxes       *boxes,
+                                       GtkSnapshot       *snapshot,
+                                       const GdkRGBA     *bg_color,
+                                       const GtkCssValue *background_image)
 {
-  gint n_values = _gtk_css_array_value_get_n_values (background_image);
-  GtkCssArea clip = _gtk_css_area_value_get 
+  const GskRoundedRect *box;
+  gint n_values;
+  GtkCssArea clip;
+    
+  n_values = _gtk_css_array_value_get_n_values (background_image);
+  clip = _gtk_css_area_value_get 
     (_gtk_css_array_value_get_nth 
-     (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), 
+     (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), 
       n_values - 1));
+  box = gtk_css_boxes_get_box (boxes, clip);
 
-  if (gsk_rounded_rect_is_rectilinear (&bg->boxes[clip]))
+  if (gsk_rounded_rect_is_rectilinear (box))
     {
       gtk_snapshot_append_color (snapshot,
                                  bg_color,
-                                 &bg->boxes[clip].bounds);
+                                 &box->bounds);
     }
   else
     {
-      gtk_snapshot_push_rounded_clip (snapshot,
-                                      &bg->boxes[clip]);
+      gtk_snapshot_push_rounded_clip (snapshot, box);
       gtk_snapshot_append_color (snapshot,
                                  bg_color,
-                                 &bg->boxes[clip].bounds);
+                                 &box->bounds);
       gtk_snapshot_pop (snapshot);
     }
 }
 
 static void
-gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg,
-                                       guint                       idx,
-                                       GtkSnapshot                *snapshot)
+gtk_theming_background_snapshot_layer (GtkCssBoxes *bg,
+                                       guint        idx,
+                                       GtkSnapshot *snapshot)
 {
   GtkCssRepeatStyle hrepeat, vrepeat;
   const GtkCssValue *pos, *repeat;
@@ -112,11 +107,11 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg,
   vrepeat = _gtk_css_background_repeat_value_get_y (repeat);
 
 
-  origin = &bg->boxes[
-               _gtk_css_area_value_get (
-                   _gtk_css_array_value_get_nth (
-                       gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN),
-                       idx))];
+  origin = gtk_css_boxes_get_box (bg,
+                                  _gtk_css_area_value_get (
+                                      _gtk_css_array_value_get_nth (
+                                          gtk_css_style_get_value (bg->style, 
GTK_CSS_PROPERTY_BACKGROUND_ORIGIN),
+                                          idx)));
 
   width = origin->bounds.size.width;
   height = origin->bounds.size.height;
@@ -124,11 +119,11 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg,
   if (width <= 0 || height <= 0)
     return;
 
-  clip = &bg->boxes[
-              _gtk_css_area_value_get (
-                                _gtk_css_array_value_get_nth (
-                                                    gtk_css_style_get_value (bg->style, 
GTK_CSS_PROPERTY_BACKGROUND_CLIP),
-                                                                      idx))];
+  clip = gtk_css_boxes_get_box (bg,
+                                _gtk_css_area_value_get (
+                                    _gtk_css_array_value_get_nth (
+                                        gtk_css_style_get_value (bg->style, 
GTK_CSS_PROPERTY_BACKGROUND_CLIP),
+                                        idx)));
 
   _gtk_css_bg_size_value_compute_size (_gtk_css_array_value_get_nth (gtk_css_style_get_value (bg->style, 
GTK_CSS_PROPERTY_BACKGROUND_SIZE), idx),
                                        image,
@@ -274,28 +269,13 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg,
   gtk_snapshot_pop (snapshot);
 }
 
-static void
-gtk_theming_background_init (GtkThemingBackground *bg,
-                             GtkCssStyle          *style,
-                             double                width,
-                             double                height)
-{
-  bg->style = style;
-
-  gtk_rounded_boxes_init_for_style (&bg->boxes[GTK_CSS_AREA_BORDER_BOX],
-                                    &bg->boxes[GTK_CSS_AREA_PADDING_BOX],
-                                    &bg->boxes[GTK_CSS_AREA_CONTENT_BOX],
-                                    style,
-                                    0, 0, width, height);
-}
-
 void
 gtk_css_style_snapshot_background (GtkCssStyle      *style,
                                    GtkSnapshot      *snapshot,
                                    gdouble           width,
                                    gdouble           height)
 {
-  GtkThemingBackground bg;
+  GtkCssBoxes boxes;
   gint idx;
   GtkCssValue *background_image;
   GtkCssValue *box_shadow;
@@ -315,13 +295,13 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
       _gtk_css_shadows_value_is_none (box_shadow))
     return;
 
-  gtk_theming_background_init (&bg, style, width, height);
+  gtk_css_boxes_init_border_box (&boxes, style, 0, 0, width, height);
 
   gtk_snapshot_push_debug (snapshot, "CSS background");
 
   gtk_css_shadows_value_snapshot_outset (box_shadow,
                                          snapshot,
-                                         &bg.boxes[GTK_CSS_AREA_BORDER_BOX]);
+                                         gtk_css_boxes_get_border_box (&boxes));
 
   blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
   number_of_layers = _gtk_css_array_value_get_n_values (background_image);
@@ -336,25 +316,25 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
     }
 
   if (!gdk_rgba_is_clear (bg_color))
-    gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image);
+    gtk_theming_background_snapshot_color (&boxes, snapshot, bg_color, background_image);
 
   for (idx = number_of_layers - 1; idx >= 0; idx--)
     {
       if (blend_mode_values[idx] == GSK_BLEND_MODE_DEFAULT)
         {
-          gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
+          gtk_theming_background_snapshot_layer (&boxes, idx, snapshot);
         }
       else
         {
           gtk_snapshot_pop (snapshot);
-          gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
+          gtk_theming_background_snapshot_layer (&boxes, idx, snapshot);
           gtk_snapshot_pop (snapshot);
         }
     }
 
   gtk_css_shadows_value_snapshot_inset (box_shadow,
                                         snapshot,
-                                        &bg.boxes[GTK_CSS_AREA_PADDING_BOX]);
+                                        gtk_css_boxes_get_padding_box (&boxes));
 
   gtk_snapshot_pop (snapshot);
 }


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