[gtk+/box-shadow: 3/5] shadow: add _gtk_box_shadow_render()



commit 82970033378c47baf6051249a782b6577310e70f
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Wed Jun 1 20:58:53 2011 -0400

    shadow: add _gtk_box_shadow_render()
    
    This supports only inset box-shadow elements for now.

 gtk/gtkshadow.c        |  135 ++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkshadowprivate.h |   17 +++++-
 2 files changed, 149 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkshadow.c b/gtk/gtkshadow.c
index ce84e4b..d0b294f 100644
--- a/gtk/gtkshadow.c
+++ b/gtk/gtkshadow.c
@@ -23,6 +23,8 @@
 
 #include "gtkshadowprivate.h"
 #include "gtkstylecontext.h"
+#include "gtkthemingengineprivate.h"
+#include "gtkthemingengine.h"
 #include "gtkpango.h"
 
 typedef struct _GtkShadowElement GtkShadowElement;
@@ -39,6 +41,42 @@ struct _GtkShadowElement {
   GtkSymbolicColor *symbolic_color;
 };
 
+/* From: http://dev.w3.org/csswg/css3-background/#box-shadow
+ *
+ * If a spread distance is defined, the shadow is [...] contracted inward by
+ * an operation [...]. Alternatively the UA may approximate the transformed
+ * shadow perimeter shape by outsetting (insetting, for inner shadows) the
+ * shadow's straight edges by the spread distance and increasing (decreasing, 
+ * for inner shadows) and flooring at zero the corner radii by the same amount.
+ */
+static void
+shadow_element_adjust_radius_for_spread (GtkShadowElement         *element,
+                                         const GtkCssBorderRadius *radius,
+                                         GtkCssBorderRadius       *adjusted_radius)
+{
+  GtkCssBorderRadius spread_radius;
+
+  spread_radius.top_left.horizontal = 
+    MAX (0, radius->top_left.horizontal - element->spread);
+  spread_radius.top_left.vertical = 
+    MAX (0, radius->top_left.vertical - element->spread);
+  spread_radius.top_right.horizontal = 
+    MAX (0, radius->top_right.horizontal - element->spread);
+  spread_radius.top_right.vertical = 
+    MAX (0, radius->top_right.vertical - element->spread);
+  spread_radius.bottom_right.horizontal = 
+    MAX (0, radius->bottom_right.horizontal - element->spread);
+  spread_radius.bottom_right.vertical = 
+    MAX (0, radius->bottom_right.vertical - element->spread);
+  spread_radius.bottom_left.horizontal = 
+    MAX (0, radius->bottom_left.horizontal - element->spread);
+  spread_radius.bottom_left.vertical = 
+    MAX (0, radius->bottom_left.vertical - element->spread);
+
+  if (adjusted_radius != NULL)
+    *adjusted_radius = spread_radius;
+}
+
 static void
 shadow_element_print (GtkShadowElement *element,
                       GString          *str)
@@ -275,3 +313,100 @@ _gtk_text_shadow_paint_layout (GtkShadow       *shadow,
   }
 }
 
+void
+_gtk_box_shadow_render (GtkShadow          *shadow,
+                        cairo_t            *cr,
+                        gdouble             x,
+                        gdouble             y,
+                        gdouble             width,
+                        gdouble             height,
+                        GtkBorder          *border,
+                        GtkCssBorderRadius *border_radius)
+{
+  GtkShadowElement *element;
+  GtkCssBorderRadius spread_radius;
+  gdouble fill_x, fill_y, fill_w, fill_h;
+  GList *l;
+
+  cairo_save (cr);
+
+  cairo_translate (cr, x, y);
+  cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+  _cairo_round_rectangle_sides (cr, border_radius,
+                                border->left,
+                                border->top,
+                                width - border->left - border->right,
+                                height - border->top - border->bottom,
+                                SIDE_ALL);
+  cairo_clip (cr);
+
+  /* render shadows starting from the last one,
+   * and the others on top.
+   */
+  for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
+    {
+      element = l->data;
+
+      if (!element->inset)
+        continue;
+
+      cairo_save (cr);
+
+      shadow_element_adjust_radius_for_spread (element,
+                                               border_radius, &spread_radius);
+
+      if (element->hoffset > 0)
+        {
+          fill_x = border->left + element->hoffset + element->spread;
+          fill_w = width - fill_x - border->right;
+        }
+      else if (element->hoffset < 0)
+        {
+          fill_x = border->left;
+          fill_w = width - border->left - border->right + element->hoffset - element->spread;
+        }
+      else
+        {
+          /* element->hoffset == 0 */
+          fill_x = border->left + element->spread;
+          fill_w = width - border->left - border->right - 2 * element->spread;
+        }
+
+      if (element->voffset > 0)
+        {
+          fill_y = border->top + element->voffset + element->spread;
+          fill_h = height - fill_y - border->bottom;
+        }
+      else if (element->hoffset < 0)
+        {
+          fill_y = border->top;
+          fill_h = height - border->top - border->bottom + element->voffset - element->spread;
+        }
+      else
+        {
+          /* element->voffset == 0 */
+          fill_y = border->top + element->spread;
+          fill_h = height - border->top - border->bottom - 2 * element->spread;
+        }
+
+      _cairo_round_rectangle_sides (cr, border_radius,
+                                    border->left,
+                                    border->top,
+                                    width - border->left - border->right,
+                                    height - border->top - border->bottom,
+                                    SIDE_ALL);
+
+      _cairo_round_rectangle_sides (cr, &spread_radius,
+                                    fill_x, fill_y,
+                                    fill_w, fill_h,
+                                    SIDE_ALL);
+
+      gdk_cairo_set_source_rgba (cr, &element->color);
+      cairo_fill (cr);
+
+      cairo_restore (cr);
+  }
+
+  cairo_restore (cr);
+}
diff --git a/gtk/gtkshadowprivate.h b/gtk/gtkshadowprivate.h
index 1594dc6..9f2af13 100644
--- a/gtk/gtkshadowprivate.h
+++ b/gtk/gtkshadowprivate.h
@@ -23,9 +23,11 @@
 #define __GTK_SHADOW_H__
 
 #include <glib-object.h>
-#include <gtk/gtkstyleproperties.h>
-#include <gtk/gtksymboliccolor.h>
-#include <gtk/gtkicontheme.h>
+
+#include "gtkstyleproperties.h"
+#include "gtksymboliccolor.h"
+#include "gtkicontheme.h"
+#include "gtkcsstypesprivate.h"
 
 G_BEGIN_DECLS
 
@@ -58,6 +60,15 @@ void       _gtk_text_shadow_paint_layout (GtkShadow       *shadow,
                                           cairo_t         *cr,
                                           PangoLayout     *layout);
 
+void       _gtk_box_shadow_render (GtkShadow          *shadow,
+                                   cairo_t            *cr,
+                                   gdouble             x,
+                                   gdouble             y,
+                                   gdouble             width,
+                                   gdouble             height,
+                                   GtkBorder          *border,
+                                   GtkCssBorderRadius *border_radius);
+
 G_END_DECLS
 
 #endif /* __GTK_SHADOW_H__ */



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