[gtk+] render: Move code for rendering builtin images



commit 1c3dd5d46bd2e33bc7bf43b28d9c57c69a1199dd
Author: Benjamin Otte <otte redhat com>
Date:   Sun Jan 18 20:24:27 2015 +0100

    render: Move code for rendering builtin images
    
    Also, make it have a generic entry point with
    gtk_css_image_builtin_draw().
    
    The only feature lost so is the drawing of shadows for spinners, but
    that will come back later.

 gtk/gtkcssimagebuiltin.c        |  794 +++++++++++++++++++++++++++++++++++++-
 gtk/gtkcssimagebuiltinprivate.h |   25 ++
 gtk/gtkrender.c                 |  818 ++++++++-------------------------------
 3 files changed, 976 insertions(+), 661 deletions(-)
---
diff --git a/gtk/gtkcssimagebuiltin.c b/gtk/gtkcssimagebuiltin.c
index 7f72ce1..ba31ec1 100644
--- a/gtk/gtkcssimagebuiltin.c
+++ b/gtk/gtkcssimagebuiltin.c
@@ -21,15 +21,728 @@
 
 #include "gtkcssimagebuiltinprivate.h"
 
+#include "gtkhslaprivate.h"
+#include "gtkrenderprivate.h"
+
+#include <math.h>
+
+#include "fallback-c89.c"
+
 G_DEFINE_TYPE (GtkCssImageBuiltin, gtk_css_image_builtin, GTK_TYPE_CSS_IMAGE)
 
 static GtkCssImage *the_one_true_image;
 
 static void
-gtk_css_image_builtin_draw (GtkCssImage        *image,
-                            cairo_t            *cr,
-                            double              width,
-                            double              height)
+gtk_css_image_builtin_draw_check (GtkCssImage            *image,
+                                  cairo_t                *cr,
+                                  double                  width,
+                                  double                  height,
+                                  GtkStateFlags           state,
+                                  const GdkRGBA *         fg_color,
+                                  const GdkRGBA *         bg_color,
+                                  const GdkRGBA *         border_color,
+                                  int                     border_width)
+{
+  gint x, y, exterior_size, interior_size, thickness, pad;
+
+  exterior_size = MIN (width, height);
+
+  if (exterior_size % 2 == 0) /* Ensure odd */
+    exterior_size -= 1;
+
+  /* FIXME: thickness */
+  thickness = 1;
+  pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
+  interior_size = MAX (1, exterior_size - 2 * pad);
+
+  if (interior_size < 7)
+    {
+      interior_size = 7;
+      pad = MAX (0, (exterior_size - interior_size) / 2);
+    }
+
+  x = - (1 + exterior_size - (gint) width) / 2;
+  y = - (1 + exterior_size - (gint) height) / 2;
+
+  if (border_width > 0)
+    {
+      cairo_set_line_width (cr, border_width);
+
+      cairo_rectangle (cr, x + 0.5, y + 0.5, exterior_size - 1, exterior_size - 1);
+      gdk_cairo_set_source_rgba (cr, bg_color);
+      cairo_fill_preserve (cr);
+
+      gdk_cairo_set_source_rgba (cr, border_color);
+      cairo_stroke (cr);
+    }
+
+  gdk_cairo_set_source_rgba (cr, fg_color);
+
+  if (state & GTK_STATE_FLAG_INCONSISTENT)
+    {
+      int line_thickness = MAX (1, (3 + interior_size * 2) / 7);
+
+      cairo_rectangle (cr,
+                      x + pad,
+                      y + pad + (1 + interior_size - line_thickness) / 2,
+                      interior_size,
+                      line_thickness);
+      cairo_fill (cr);
+    }
+  else
+    {
+      if (state & GTK_STATE_FLAG_CHECKED)
+        {
+          cairo_translate (cr,
+                           x + pad, y + pad);
+
+          cairo_scale (cr, interior_size / 7., interior_size / 7.);
+
+          cairo_rectangle (cr, 0, 0, 7, 7);
+          cairo_clip (cr);
+
+          cairo_move_to  (cr, 7.0, 0.0);
+          cairo_line_to  (cr, 7.5, 1.0);
+          cairo_curve_to (cr, 5.3, 2.0,
+                          4.3, 4.0,
+                          3.5, 7.0);
+          cairo_curve_to (cr, 3.0, 5.7,
+                          1.3, 4.7,
+                          0.0, 4.7);
+          cairo_line_to  (cr, 0.2, 3.5);
+          cairo_curve_to (cr, 1.1, 3.5,
+                          2.3, 4.3,
+                          3.0, 5.0);
+          cairo_curve_to (cr, 1.0, 3.9,
+                          2.4, 4.1,
+                          3.2, 4.9);
+          cairo_curve_to (cr, 3.5, 3.1,
+                          5.2, 2.0,
+                          7.0, 0.0);
+
+          cairo_fill (cr);
+        }
+    }
+}
+
+static void
+gtk_css_image_builtin_draw_option (GtkCssImage            *image,
+                                   cairo_t                *cr,
+                                   double                  width,
+                                   double                  height,
+                                   GtkStateFlags           state,
+                                   const GdkRGBA *         fg_color,
+                                   const GdkRGBA *         bg_color,
+                                   const GdkRGBA *         border_color,
+                                   int                     border_width)
+{
+  gint x, y, exterior_size, interior_size, thickness, pad;
+
+  exterior_size = MIN (width, height);
+
+  if (exterior_size % 2 == 0) /* Ensure odd */
+    exterior_size -= 1;
+
+  x = - (1 + exterior_size - width) / 2;
+  y = - (1 + exterior_size - height) / 2;
+
+  if (border_width > 0)
+    {
+      cairo_set_line_width (cr, border_width);
+
+      cairo_new_sub_path (cr);
+      cairo_arc (cr,
+                 x + exterior_size / 2.,
+                 y + exterior_size / 2.,
+                 (exterior_size - 1) / 2.,
+                 0, 2 * G_PI);
+
+      gdk_cairo_set_source_rgba (cr, bg_color);
+      cairo_fill_preserve (cr);
+
+      gdk_cairo_set_source_rgba (cr, border_color);
+      cairo_stroke (cr);
+    }
+
+  gdk_cairo_set_source_rgba (cr, fg_color);
+
+  /* FIXME: thickness */
+  thickness = 1;
+
+  if (state & GTK_STATE_FLAG_INCONSISTENT)
+    {
+      gint line_thickness;
+
+      pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
+      interior_size = MAX (1, exterior_size - 2 * pad);
+
+      if (interior_size < 7)
+        {
+          interior_size = 7;
+          pad = MAX (0, (exterior_size - interior_size) / 2);
+        }
+
+      line_thickness = MAX (1, (3 + interior_size * 2) / 7);
+
+      cairo_rectangle (cr,
+                       x + pad,
+                       y + pad + (interior_size - line_thickness) / 2.,
+                       interior_size,
+                       line_thickness);
+      cairo_fill (cr);
+    }
+  if (state & GTK_STATE_FLAG_CHECKED)
+    {
+      pad = thickness + MAX (1, 2 * (exterior_size - 2 * thickness) / 9);
+      interior_size = MAX (1, exterior_size - 2 * pad);
+
+      if (interior_size < 5)
+        {
+          interior_size = 7;
+          pad = MAX (0, (exterior_size - interior_size) / 2);
+        }
+
+      cairo_new_sub_path (cr);
+      cairo_arc (cr,
+                 x + pad + interior_size / 2.,
+                 y + pad + interior_size / 2.,
+                 interior_size / 2.,
+                 0, 2 * G_PI);
+      cairo_fill (cr);
+    }
+}
+
+static void
+gtk_css_image_builtin_draw_arrow (GtkCssImage            *image,
+                                  cairo_t                *cr,
+                                  double                  width,
+                                  double                  height,
+                                  const GdkRGBA *         color)
+{
+  double line_width;
+  double size;
+
+  size = MIN (width, height);
+
+  cairo_translate (cr, width / 2.0 + size / 4.0, height / 2.0);
+
+  line_width = size / 3.0 / sqrt (2);
+  cairo_set_line_width (cr, line_width);
+  cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+
+  cairo_scale (cr,
+               (size / (size + line_width)),
+               (size / (size + line_width)));
+
+  cairo_move_to (cr, -size / 2.0, -size / 2.0);
+  cairo_rel_line_to (cr, size / 2.0, size / 2.0);
+  cairo_rel_line_to (cr, - size / 2.0, size / 2.0);
+
+  gdk_cairo_set_source_rgba (cr, color);
+  cairo_stroke (cr);
+}
+
+static void
+gtk_css_image_builtin_draw_expander (GtkCssImage            *image,
+                                     cairo_t                *cr,
+                                     double                  width,
+                                     double                  height,
+                                     GtkStateFlags           state,
+                                     GtkCssImageBuiltinType  image_type,
+                                     const GdkRGBA *         fg_color,
+                                     const GdkRGBA *         border_color)
+{
+  double vertical_overshoot;
+  int diameter;
+  double radius;
+  double interp;               /* interpolation factor for center position */
+  double x_double_horz, y_double_horz;
+  double x_double_vert, y_double_vert;
+  double x_double, y_double;
+  gdouble angle;
+  gint line_width;
+  gboolean is_rtl;
+  gdouble progress;
+
+  is_rtl = (state & GTK_STATE_FLAG_DIR_RTL);
+  line_width = 1;
+  progress = (state & GTK_STATE_FLAG_CHECKED) ? 1 : 0;
+
+  if (image_type != GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL)
+    {
+      if (is_rtl)
+        angle = (G_PI) - ((G_PI / 2) * progress);
+      else
+        angle = (G_PI / 2) * progress;
+    }
+  else
+    {
+      if (is_rtl)
+        angle = (G_PI / 2) + ((G_PI / 2) * progress);
+      else
+        angle = (G_PI / 2) - ((G_PI / 2) * progress);
+    }
+
+  interp = progress;
+
+  /* Compute distance that the stroke extends beyonds the end
+   * of the triangle we draw.
+   */
+  vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
+
+  /* For odd line widths, we end the vertical line of the triangle
+   * at a half pixel, so we round differently.
+   */
+  if (line_width % 2 == 1)
+    vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
+  else
+    vertical_overshoot = ceil (vertical_overshoot);
+
+  /* Adjust the size of the triangle we draw so that the entire stroke fits
+   */
+  diameter = (gint) MAX (3, width - 2 * vertical_overshoot);
+
+  /* If the line width is odd, we want the diameter to be even,
+   * and vice versa, so force the sum to be odd. This relationship
+   * makes the point of the triangle look right.
+   */
+  diameter -= (1 - (diameter + line_width) % 2);
+
+  radius = diameter / 2.;
+
+  /* Adjust the center so that the stroke is properly aligned with
+   * the pixel grid. The center adjustment is different for the
+   * horizontal and vertical orientations. For intermediate positions
+   * we interpolate between the two.
+   */
+  x_double_vert = floor ((width / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
+  y_double_vert = (height / 2) - 0.5;
+
+  x_double_horz = (width / 2) - 0.5;
+  y_double_horz = floor ((height / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
+
+  x_double = x_double_vert * (1 - interp) + x_double_horz * interp;
+  y_double = y_double_vert * (1 - interp) + y_double_horz * interp;
+
+  cairo_translate (cr, x_double, y_double);
+  cairo_rotate (cr, angle);
+
+  cairo_move_to (cr, - radius / 2., - radius);
+  cairo_line_to (cr,   radius / 2.,   0);
+  cairo_line_to (cr, - radius / 2.,   radius);
+  cairo_close_path (cr);
+
+  cairo_set_line_width (cr, line_width);
+
+  gdk_cairo_set_source_rgba (cr, fg_color);
+
+  cairo_fill_preserve (cr);
+
+  gdk_cairo_set_source_rgba (cr, border_color);
+  cairo_stroke (cr);
+}
+
+static void
+color_shade (const GdkRGBA *color,
+             gdouble        factor,
+             GdkRGBA       *color_return)
+{
+  GtkHSLA hsla;
+
+  _gtk_hsla_init_from_rgba (&hsla, color);
+  _gtk_hsla_shade (&hsla, &hsla, factor);
+  _gdk_rgba_init_from_hsla (color_return, &hsla);
+}
+
+static void
+render_dot (cairo_t       *cr,
+            const GdkRGBA *lighter,
+            const GdkRGBA *darker,
+            gdouble        x,
+            gdouble        y,
+            gdouble        size)
+{
+  size = CLAMP ((gint) size, 2, 3);
+
+  if (size == 2)
+    {
+      gdk_cairo_set_source_rgba (cr, lighter);
+      cairo_rectangle (cr, x, y, 1, 1);
+      cairo_rectangle (cr, x + 1, y + 1, 1, 1);
+      cairo_fill (cr);
+    }
+  else if (size == 3)
+    {
+      gdk_cairo_set_source_rgba (cr, lighter);
+      cairo_rectangle (cr, x, y, 2, 1);
+      cairo_rectangle (cr, x, y, 1, 2);
+      cairo_fill (cr);
+
+      gdk_cairo_set_source_rgba (cr, darker);
+      cairo_rectangle (cr, x + 1, y + 1, 2, 1);
+      cairo_rectangle (cr, x + 2, y, 1, 2);
+      cairo_fill (cr);
+    }
+}
+
+static void
+add_path_line (cairo_t        *cr,
+               gdouble         x1,
+               gdouble         y1,
+               gdouble         x2,
+               gdouble         y2)
+{
+  /* Adjust endpoints */
+  if (y1 == y2)
+    {
+      y1 += 0.5;
+      y2 += 0.5;
+      x2 += 1;
+    }
+  else if (x1 == x2)
+    {
+      x1 += 0.5;
+      x2 += 0.5;
+      y2 += 1;
+    }
+
+  cairo_move_to (cr, x1, y1);
+  cairo_line_to (cr, x2, y2);
+}
+
+void
+gtk_css_image_builtin_draw_grip (GtkCssImage      *image,
+                                 cairo_t          *cr,
+                                 double            width,
+                                 double            height,
+                                 GtkJunctionSides  sides,
+                                 const GdkRGBA    *bg_color)
+{
+  GdkRGBA lighter, darker;
+
+  cairo_set_line_width (cr, 1.0);
+
+  color_shade (bg_color, 0.7, &darker);
+  color_shade (bg_color, 1.3, &lighter);
+
+  /* reduce confusing values to a meaningful state */
+  if ((sides & (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT)) == 
(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT))
+    sides &= ~GTK_JUNCTION_CORNER_TOPLEFT;
+
+  if ((sides & (GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT)) == 
(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT))
+    sides &= ~GTK_JUNCTION_CORNER_TOPRIGHT;
+
+  if (sides == 0)
+    sides = GTK_JUNCTION_CORNER_BOTTOMRIGHT;
+
+  /* align drawing area to the connected side */
+  if (sides == GTK_JUNCTION_LEFT)
+    {
+      if (height < width)
+        width = height;
+    }
+  else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
+    {
+      if (width < height)
+        height = width;
+      else if (height < width)
+        width = height;
+    }
+  else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
+    {
+      /* make it square, aligning to bottom left */
+      if (width < height)
+        {
+          cairo_translate (cr, 0, height - width);
+          height = width;
+        }
+      else if (height < width)
+        width = height;
+    }
+  else if (sides == GTK_JUNCTION_RIGHT)
+    {
+      /* aligning to right */
+      if (height < width)
+        {
+          cairo_translate (cr, width - height, 0);
+          width = height;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
+    {
+      if (width < height)
+        height = width;
+      else if (height < width)
+        {
+          cairo_translate (cr, width - height, 0);
+          width = height;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
+    {
+      /* make it square, aligning to bottom right */
+      if (width < height)
+        {
+          cairo_translate (cr, 0, height - width);
+          height = width;
+        }
+      else if (height < width)
+        {
+          cairo_translate (cr, width - height, 0);
+          width = height;
+        }
+    }
+  else if (sides == GTK_JUNCTION_TOP)
+    {
+      if (width < height)
+        height = width;
+    }
+  else if (sides == GTK_JUNCTION_BOTTOM)
+    {
+      /* align to bottom */
+      if (width < height)
+        {
+          cairo_translate (cr, 0, height - width);
+          height = width;
+        }
+    }
+  else
+    g_assert_not_reached ();
+
+  if (sides == GTK_JUNCTION_LEFT ||
+      sides == GTK_JUNCTION_RIGHT)
+    {
+      gint xi;
+
+      xi = 0;
+
+      while (xi < width)
+        {
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, 0, 0, 0, height);
+          cairo_stroke (cr);
+          xi++;
+
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, xi, 0, xi, height);
+          cairo_stroke (cr);
+          xi += 2;
+        }
+    }
+  else if (sides == GTK_JUNCTION_TOP ||
+           sides == GTK_JUNCTION_BOTTOM)
+    {
+      gint yi;
+
+      yi = 0;
+
+      while (yi < height)
+        {
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, 0, yi, width, yi);
+          cairo_stroke (cr);
+          yi++;
+
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, 0, yi, width, yi);
+          cairo_stroke (cr);
+          yi += 2;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
+    {
+      gint xi, yi;
+
+      xi = width;
+      yi = height;
+
+      while (xi > 3)
+        {
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, xi, 0, 0, yi);
+          cairo_stroke (cr);
+
+          --xi;
+          --yi;
+
+          add_path_line (cr, xi, 0, 0, yi);
+          cairo_stroke (cr);
+
+          --xi;
+          --yi;
+
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, xi, 0, 0, yi);
+          cairo_stroke (cr);
+
+          xi -= 3;
+          yi -= 3;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
+    {
+      gint xi, yi;
+
+      xi = 0;
+      yi = height;
+
+      while (xi < (width - 3))
+        {
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, xi, 0, width, yi);
+          cairo_stroke (cr);
+
+          ++xi;
+          --yi;
+
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, xi, 0, width, yi);
+          cairo_stroke (cr);
+
+          ++xi;
+          --yi;
+
+          add_path_line (cr, xi, 0, width, yi);
+          cairo_stroke (cr);
+
+          xi += 3;
+          yi -= 3;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
+    {
+      gint xi, yi;
+
+      xi = width;
+      yi = 0;
+
+      while (xi > 3)
+        {
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, 0, yi, xi, height);
+          cairo_stroke (cr);
+
+          --xi;
+          ++yi;
+
+          add_path_line (cr, 0, yi, xi, height);
+          cairo_stroke (cr);
+
+          --xi;
+          ++yi;
+
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, 0, yi, xi, height);
+          cairo_stroke (cr);
+
+          xi -= 3;
+          yi += 3;
+        }
+    }
+  else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
+    {
+      gint xi, yi;
+
+      xi = 0;
+      yi = 0;
+
+      while (xi < (width - 3))
+        {
+          gdk_cairo_set_source_rgba (cr, &lighter);
+          add_path_line (cr, xi, height, width, yi);
+          cairo_stroke (cr);
+
+          ++xi;
+          ++yi;
+
+          gdk_cairo_set_source_rgba (cr, &darker);
+          add_path_line (cr, xi, height, width, yi);
+          cairo_stroke (cr);
+
+          ++xi;
+          ++yi;
+
+          add_path_line (cr, xi, height, width, yi);
+          cairo_stroke (cr);
+
+          xi += 3;
+          yi += 3;
+        }
+    }
+}
+
+void
+gtk_css_image_builtin_draw_pane_separator (GtkCssImage   *image,
+                                           cairo_t       *cr,
+                                           double         width,
+                                           double         height,
+                                           const GdkRGBA *bg_color)
+{
+  GdkRGBA lighter, darker;
+  gint xx, yy;
+
+  cairo_set_line_width (cr, 1.0);
+
+  color_shade (bg_color, 0.7, &darker);
+  color_shade (bg_color, 1.3, &lighter);
+
+  if (width > height)
+    for (xx = width / 2 - 15; xx <= width / 2 + 15; xx += 5)
+      render_dot (cr, &lighter, &darker, xx, height / 2 - 1, 3);
+  else
+    for (yy = height / 2 - 15; yy <= height / 2 + 15; yy += 5)
+      render_dot (cr, &lighter, &darker, width / 2 - 1, yy, 3);
+}
+
+void
+gtk_css_image_builtin_draw_handle (GtkCssImage   *image,
+                                   cairo_t       *cr,
+                                   double         width,
+                                   double         height,
+                                   const GdkRGBA *bg_color)
+{
+  GdkRGBA lighter, darker;
+  gint xx, yy;
+
+  cairo_set_line_width (cr, 1.0);
+
+  color_shade (bg_color, 0.7, &darker);
+  color_shade (bg_color, 1.3, &lighter);
+
+  for (yy = 0; yy < height; yy += 3)
+    for (xx = 0; xx < width; xx += 6)
+      {
+        render_dot (cr, &lighter, &darker, xx, yy, 2);
+        render_dot (cr, &lighter, &darker, xx + 3, yy + 1, 2);
+      }
+}
+
+static void
+gtk_css_image_builtin_draw_spinner (GtkCssImage     *image,
+                                    cairo_t         *cr,
+                                    double           width,
+                                    double           height,
+                                    const GdkRGBA   *color)
+{
+  gdouble radius;
+
+  radius = MIN (width / 2, height / 2);
+
+  cairo_save (cr);
+  cairo_translate (cr, width / 2, height / 2);
+
+  gdk_cairo_set_source_rgba (cr, color);
+  gtk_render_paint_spinner (cr, radius, -1);
+
+  cairo_restore (cr);
+}
+
+static void
+gtk_css_image_builtin_real_draw (GtkCssImage        *image,
+                                 cairo_t            *cr,
+                                 double              width,
+                                 double              height)
 {
   /* It's a builtin image, other code will draw things */
 }
@@ -99,7 +812,7 @@ gtk_css_image_builtin_class_init (GtkCssImageBuiltinClass *klass)
   GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  image_class->draw = gtk_css_image_builtin_draw;
+  image_class->draw = gtk_css_image_builtin_real_draw;
   image_class->parse = gtk_css_image_builtin_parse;
   image_class->print = gtk_css_image_builtin_print;
   image_class->compute = gtk_css_image_builtin_compute;
@@ -125,3 +838,74 @@ gtk_css_image_builtin_new (void)
   return the_one_true_image;
 }
 
+void
+gtk_css_image_builtin_draw (GtkCssImage            *image,
+                            cairo_t                *cr,
+                            double                  width,
+                            double                  height,
+                            GtkCssImageBuiltinType  image_type,
+                            GtkStateFlags           state,
+                            GtkJunctionSides        sides,
+                            const GdkRGBA *         fg_color,
+                            const GdkRGBA *         bg_color,
+                            const GdkRGBA *         border_color,
+                            int                     border_width)
+{
+  switch (image_type)
+  {
+  default:
+    g_assert_not_reached ();
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_NONE:
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_CHECK:
+    gtk_css_image_builtin_draw_check (image, cr,
+                                      width, height,
+                                      state,
+                                      fg_color, bg_color,
+                                      border_color, border_width);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_OPTION:
+    gtk_css_image_builtin_draw_option (image, cr,
+                                       width, height,
+                                       state,
+                                       fg_color, bg_color,
+                                       border_color, border_width);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_ARROW:
+    gtk_css_image_builtin_draw_arrow (image, cr,
+                                      width, height,
+                                      fg_color);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL:
+  case GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL:
+    gtk_css_image_builtin_draw_expander (image, cr,
+                                         width, height,
+                                         state,
+                                         image_type,
+                                         fg_color, border_color);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_GRIP:
+    gtk_css_image_builtin_draw_grip (image, cr,
+                                     width, height,
+                                     sides,
+                                     bg_color);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_PANE_SEPARATOR:
+    gtk_css_image_builtin_draw_pane_separator (image, cr,
+                                               width, height,
+                                               bg_color);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_HANDLE:
+    gtk_css_image_builtin_draw_handle (image, cr,
+                                       width, height,
+                                       bg_color);
+    break;
+  case GTK_CSS_IMAGE_BUILTIN_SPINNER:
+    gtk_css_image_builtin_draw_spinner (image, cr,
+                                        width, height,
+                                        fg_color);
+    break;
+  }
+}
+
diff --git a/gtk/gtkcssimagebuiltinprivate.h b/gtk/gtkcssimagebuiltinprivate.h
index 294a83b..1ad6174 100644
--- a/gtk/gtkcssimagebuiltinprivate.h
+++ b/gtk/gtkcssimagebuiltinprivate.h
@@ -25,6 +25,19 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+  GTK_CSS_IMAGE_BUILTIN_NONE,
+  GTK_CSS_IMAGE_BUILTIN_CHECK,
+  GTK_CSS_IMAGE_BUILTIN_OPTION,
+  GTK_CSS_IMAGE_BUILTIN_ARROW,
+  GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL,
+  GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL,
+  GTK_CSS_IMAGE_BUILTIN_GRIP,
+  GTK_CSS_IMAGE_BUILTIN_PANE_SEPARATOR,
+  GTK_CSS_IMAGE_BUILTIN_HANDLE,
+  GTK_CSS_IMAGE_BUILTIN_SPINNER
+} GtkCssImageBuiltinType;
+
 #define GTK_TYPE_CSS_IMAGE_BUILTIN           (gtk_css_image_builtin_get_type ())
 #define GTK_CSS_IMAGE_BUILTIN(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_BUILTIN, 
GtkCssImageBuiltin))
 #define GTK_CSS_IMAGE_BUILTIN_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_BUILTIN, 
GtkCssImageBuiltinClass))
@@ -49,6 +62,18 @@ GType          gtk_css_image_builtin_get_type              (void) G_GNUC_CONST;
 
 GtkCssImage *  gtk_css_image_builtin_new                   (void);
 
+void           gtk_css_image_builtin_draw                  (GtkCssImage                 *image,
+                                                            cairo_t                     *cr,
+                                                            double                       width,
+                                                            double                       height,
+                                                            GtkCssImageBuiltinType       image_type,
+                                                            GtkStateFlags                state,
+                                                            GtkJunctionSides             sides,
+                                                            const GdkRGBA               *fg_color,
+                                                            const GdkRGBA               *bg_color,
+                                                            const GdkRGBA               *border_color,
+                                                            int                          border_width);
+
 G_END_DECLS
 
 #endif /* __GTK_CSS_IMAGE_BUILTIN_PRIVATE_H__ */
diff --git a/gtk/gtkrender.c b/gtk/gtkrender.c
index ea264ab..15b2a8b 100644
--- a/gtk/gtkrender.c
+++ b/gtk/gtkrender.c
@@ -94,112 +94,42 @@ gtk_do_render_check (GtkStyleContext *context,
                      gdouble          width,
                      gdouble          height)
 {
-  const GdkRGBA *fg_color, *bg_color;
-  GtkStateFlags flags;
-  gint exterior_size, interior_size, thickness, pad;
   GtkBorderStyle border_style;
-  GtkBorder border;
   gint border_width;
 
   if (render_icon_image (context, cr, x, y, width, height))
     return;
 
-  flags = gtk_style_context_get_state (context);
-  cairo_save (cr);
-
-  fg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR));
-  bg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR));
-  border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
-  border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
-  border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
-  border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
   border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
-
-  border_width = MIN (MIN (border.top, border.bottom),
-                      MIN (border.left, border.right));
-  exterior_size = MIN (width, height);
-
-  if (exterior_size % 2 == 0) /* Ensure odd */
-    exterior_size -= 1;
-
-  /* FIXME: thickness */
-  thickness = 1;
-  pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
-  interior_size = MAX (1, exterior_size - 2 * pad);
-
-  if (interior_size < 7)
-    {
-      interior_size = 7;
-      pad = MAX (0, (exterior_size - interior_size) / 2);
-    }
-
-  x -= (1 + exterior_size - (gint) width) / 2;
-  y -= (1 + exterior_size - (gint) height) / 2;
-
   if (border_style == GTK_BORDER_STYLE_SOLID)
     {
-      const GdkRGBA *border_color;
+      GtkBorder border;
 
-      cairo_set_line_width (cr, border_width);
-      border_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR));
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
 
-      cairo_rectangle (cr, x + 0.5, y + 0.5, exterior_size - 1, exterior_size - 1);
-      gdk_cairo_set_source_rgba (cr, bg_color);
-      cairo_fill_preserve (cr);
-
-      gdk_cairo_set_source_rgba (cr, border_color);
-      cairo_stroke (cr);
-    }
-
-  gdk_cairo_set_source_rgba (cr, fg_color);
-
-  if (flags & GTK_STATE_FLAG_INCONSISTENT)
-    {
-      int line_thickness = MAX (1, (3 + interior_size * 2) / 7);
-
-      cairo_rectangle (cr,
-                      x + pad,
-                      y + pad + (1 + interior_size - line_thickness) / 2,
-                      interior_size,
-                      line_thickness);
-      cairo_fill (cr);
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
     }
   else
     {
-      if (flags & GTK_STATE_FLAG_CHECKED)
-        {
-          cairo_translate (cr,
-                           x + pad, y + pad);
-
-          cairo_scale (cr, interior_size / 7., interior_size / 7.);
-
-          cairo_rectangle (cr, 0, 0, 7, 7);
-          cairo_clip (cr);
-
-          cairo_move_to  (cr, 7.0, 0.0);
-          cairo_line_to  (cr, 7.5, 1.0);
-          cairo_curve_to (cr, 5.3, 2.0,
-                          4.3, 4.0,
-                          3.5, 7.0);
-          cairo_curve_to (cr, 3.0, 5.7,
-                          1.3, 4.7,
-                          0.0, 4.7);
-          cairo_line_to  (cr, 0.2, 3.5);
-          cairo_curve_to (cr, 1.1, 3.5,
-                          2.3, 4.3,
-                          3.0, 5.0);
-          cairo_curve_to (cr, 1.0, 3.9,
-                          2.4, 4.1,
-                          3.2, 4.9);
-          cairo_curve_to (cr, 3.5, 3.1,
-                          5.2, 2.0,
-                          7.0, 0.0);
-
-          cairo_fill (cr);
-        }
+      border_width = 0;
     }
 
-  cairo_restore (cr);
+  cairo_translate (cr, x, y);
+
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              width, height,
+                              GTK_CSS_IMAGE_BUILTIN_OPTION,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**
@@ -253,106 +183,42 @@ gtk_do_render_option (GtkStyleContext *context,
                       gdouble          width,
                       gdouble          height)
 {
-  GtkStateFlags flags;
-  const GdkRGBA *fg_color, *bg_color;
-  gint exterior_size, interior_size, pad, thickness, border_width;
   GtkBorderStyle border_style;
-  GtkBorder border;
+  gint border_width;
 
   if (render_icon_image (context, cr, x, y, width, height))
     return;
 
-  flags = gtk_style_context_get_state (context);
-
-  cairo_save (cr);
-
-  fg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR));
-  bg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR));
-  border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
-  border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
-  border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
-  border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
   border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
-
-  exterior_size = MIN (width, height);
-  border_width = MIN (MIN (border.top, border.bottom),
-                      MIN (border.left, border.right));
-
-  if (exterior_size % 2 == 0) /* Ensure odd */
-    exterior_size -= 1;
-
-  x -= (1 + exterior_size - width) / 2;
-  y -= (1 + exterior_size - height) / 2;
-
   if (border_style == GTK_BORDER_STYLE_SOLID)
     {
-      const GdkRGBA *border_color;
-
-      cairo_set_line_width (cr, border_width);
-      border_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR));
+      GtkBorder border;
 
-      cairo_new_sub_path (cr);
-      cairo_arc (cr,
-                 x + exterior_size / 2.,
-                 y + exterior_size / 2.,
-                 (exterior_size - 1) / 2.,
-                 0, 2 * G_PI);
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
 
-      gdk_cairo_set_source_rgba (cr, bg_color);
-      cairo_fill_preserve (cr);
-
-      gdk_cairo_set_source_rgba (cr, border_color);
-      cairo_stroke (cr);
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
     }
-
-  gdk_cairo_set_source_rgba (cr, fg_color);
-
-  /* FIXME: thickness */
-  thickness = 1;
-
-  if (flags & GTK_STATE_FLAG_INCONSISTENT)
+  else
     {
-      gint line_thickness;
-
-      pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
-      interior_size = MAX (1, exterior_size - 2 * pad);
-
-      if (interior_size < 7)
-        {
-          interior_size = 7;
-          pad = MAX (0, (exterior_size - interior_size) / 2);
-        }
-
-      line_thickness = MAX (1, (3 + interior_size * 2) / 7);
-
-      cairo_rectangle (cr,
-                       x + pad,
-                       y + pad + (interior_size - line_thickness) / 2.,
-                       interior_size,
-                       line_thickness);
-      cairo_fill (cr);
+      border_width = 0;
     }
-  if (flags & GTK_STATE_FLAG_CHECKED)
-    {
-      pad = thickness + MAX (1, 2 * (exterior_size - 2 * thickness) / 9);
-      interior_size = MAX (1, exterior_size - 2 * pad);
 
-      if (interior_size < 5)
-        {
-          interior_size = 7;
-          pad = MAX (0, (exterior_size - interior_size) / 2);
-        }
-
-      cairo_new_sub_path (cr);
-      cairo_arc (cr,
-                 x + pad + interior_size / 2.,
-                 y + pad + interior_size / 2.,
-                 interior_size / 2.,
-                 0, 2 * G_PI);
-      cairo_fill (cr);
-    }
+  cairo_translate (cr, x, y);
 
-  cairo_restore (cr);
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              width, height,
+                              GTK_CSS_IMAGE_BUILTIN_CHECK,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**
@@ -404,36 +270,44 @@ gtk_do_render_arrow (GtkStyleContext *context,
                      gdouble          y,
                      gdouble          size)
 {
-  double line_width;
-  const GdkRGBA *color;
+  GtkBorderStyle border_style;
+  gint border_width;
 
   if (render_icon_image (context, cr, x, y, size, size))
     return;
 
-  cairo_save (cr);
+  border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
+  if (border_style == GTK_BORDER_STYLE_SOLID)
+    {
+      GtkBorder border;
 
-  line_width = size / 3.0 / sqrt (2);
-  cairo_set_line_width (cr, line_width);
-  cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
-  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
+
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
+    }
+  else
+    {
+      border_width = 0;
+    }
 
   cairo_translate (cr, x + size / 2.0, y + size / 2.0);
   cairo_rotate (cr, angle - G_PI_2);
-  cairo_translate (cr, size / 4.0, 0);
-
-  cairo_scale (cr,
-               (size / (size + line_width)),
-               (size / (size + line_width)));
-
-  cairo_move_to (cr, -size / 2.0, -size / 2.0);
-  cairo_rel_line_to (cr, size / 2.0, size / 2.0);
-  cairo_rel_line_to (cr, - size / 2.0, size / 2.0);
-
-  color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR));
-  gdk_cairo_set_source_rgba (cr, color);
-  cairo_stroke (cr);
-
-  cairo_restore (cr);
+  cairo_translate (cr, - size / 2.0, - size / 2.0);
+
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              size, size,
+                              GTK_CSS_IMAGE_BUILTIN_ARROW,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**
@@ -479,18 +353,6 @@ gtk_render_arrow (GtkStyleContext *context,
   cairo_restore (cr);
 }
 
-static void
-color_shade (const GdkRGBA *color,
-             gdouble        factor,
-             GdkRGBA       *color_return)
-{
-  GtkHSLA hsla;
-
-  _gtk_hsla_init_from_rgba (&hsla, color);
-  _gtk_hsla_shade (&hsla, &hsla, factor);
-  _gdk_rgba_init_from_hsla (color_return, &hsla);
-}
-
 /**
  * gtk_render_background:
  * @context: a #GtkStyleContext
@@ -586,107 +448,44 @@ gtk_do_render_expander (GtkStyleContext *context,
                         gdouble          width,
                         gdouble          height)
 {
-  GtkStateFlags flags;
-  const GdkRGBA *outline_color, *fg_color;
-  double vertical_overshoot;
-  int diameter;
-  double radius;
-  double interp;               /* interpolation factor for center position */
-  double x_double_horz, y_double_horz;
-  double x_double_vert, y_double_vert;
-  double x_double, y_double;
-  gdouble angle;
-  gint line_width;
-  gboolean is_rtl;
-  gdouble progress;
+  GtkBorderStyle border_style;
+  gint border_width;
 
   if (render_icon_image (context, cr, x, y, width, height))
     return;
 
-  cairo_save (cr);
-  flags = gtk_style_context_get_state (context);
-
-  fg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR));
-  outline_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR));
+  border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
+  if (border_style == GTK_BORDER_STYLE_SOLID)
+    {
+      GtkBorder border;
 
-  is_rtl = (gtk_style_context_get_state (context) & GTK_STATE_FLAG_DIR_RTL);
-  line_width = 1;
-  progress = (flags & GTK_STATE_FLAG_CHECKED) ? 1 : 0;
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
 
-  if (!gtk_style_context_has_class (context, GTK_STYLE_CLASS_HORIZONTAL))
-    {
-      if (is_rtl)
-        angle = (G_PI) - ((G_PI / 2) * progress);
-      else
-        angle = (G_PI / 2) * progress;
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
     }
   else
     {
-      if (is_rtl)
-        angle = (G_PI / 2) + ((G_PI / 2) * progress);
-      else
-        angle = (G_PI / 2) - ((G_PI / 2) * progress);
+      border_width = 0;
     }
 
-  interp = progress;
-
-  /* Compute distance that the stroke extends beyonds the end
-   * of the triangle we draw.
-   */
-  vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
-
-  /* For odd line widths, we end the vertical line of the triangle
-   * at a half pixel, so we round differently.
-   */
-  if (line_width % 2 == 1)
-    vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
-  else
-    vertical_overshoot = ceil (vertical_overshoot);
-
-  /* Adjust the size of the triangle we draw so that the entire stroke fits
-   */
-  diameter = (gint) MAX (3, width - 2 * vertical_overshoot);
-
-  /* If the line width is odd, we want the diameter to be even,
-   * and vice versa, so force the sum to be odd. This relationship
-   * makes the point of the triangle look right.
-   */
-  diameter -= (1 - (diameter + line_width) % 2);
-
-  radius = diameter / 2.;
-
-  /* Adjust the center so that the stroke is properly aligned with
-   * the pixel grid. The center adjustment is different for the
-   * horizontal and vertical orientations. For intermediate positions
-   * we interpolate between the two.
-   */
-  x_double_vert = floor ((x + width / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
-  y_double_vert = (y + height / 2) - 0.5;
-
-  x_double_horz = (x + width / 2) - 0.5;
-  y_double_horz = floor ((y + height / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
-
-  x_double = x_double_vert * (1 - interp) + x_double_horz * interp;
-  y_double = y_double_vert * (1 - interp) + y_double_horz * interp;
-
-  cairo_translate (cr, x_double, y_double);
-  cairo_rotate (cr, angle);
-
-  cairo_move_to (cr, - radius / 2., - radius);
-  cairo_line_to (cr,   radius / 2.,   0);
-  cairo_line_to (cr, - radius / 2.,   radius);
-  cairo_close_path (cr);
-
-  cairo_set_line_width (cr, line_width);
-
-  gdk_cairo_set_source_rgba (cr, fg_color);
-
-  cairo_fill_preserve (cr);
-
-  gdk_cairo_set_source_rgba (cr, outline_color);
-  cairo_stroke (cr);
+  cairo_translate (cr, x, y);
 
-  cairo_restore (cr);
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              width, height,
+                              gtk_style_context_has_class (context, "horizontal")
+                              ? GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL
+                              : GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**
@@ -1228,62 +1027,6 @@ gtk_render_extension (GtkStyleContext *context,
 }
 
 static void
-render_dot (cairo_t       *cr,
-            const GdkRGBA *lighter,
-            const GdkRGBA *darker,
-            gdouble        x,
-            gdouble        y,
-            gdouble        size)
-{
-  size = CLAMP ((gint) size, 2, 3);
-
-  if (size == 2)
-    {
-      gdk_cairo_set_source_rgba (cr, lighter);
-      cairo_rectangle (cr, x, y, 1, 1);
-      cairo_rectangle (cr, x + 1, y + 1, 1, 1);
-      cairo_fill (cr);
-    }
-  else if (size == 3)
-    {
-      gdk_cairo_set_source_rgba (cr, lighter);
-      cairo_rectangle (cr, x, y, 2, 1);
-      cairo_rectangle (cr, x, y, 1, 2);
-      cairo_fill (cr);
-
-      gdk_cairo_set_source_rgba (cr, darker);
-      cairo_rectangle (cr, x + 1, y + 1, 2, 1);
-      cairo_rectangle (cr, x + 2, y, 1, 2);
-      cairo_fill (cr);
-    }
-}
-
-static void
-add_path_line (cairo_t        *cr,
-               gdouble         x1,
-               gdouble         y1,
-               gdouble         x2,
-               gdouble         y2)
-{
-  /* Adjust endpoints */
-  if (y1 == y2)
-    {
-      y1 += 0.5;
-      y2 += 0.5;
-      x2 += 1;
-    }
-  else if (x1 == x2)
-    {
-      x1 += 0.5;
-      x2 += 0.5;
-      y2 += 1;
-    }
-
-  cairo_move_to (cr, x1, y1);
-  cairo_line_to (cr, x2, y2);
-}
-
-static void
 gtk_do_render_handle (GtkStyleContext *context,
                       cairo_t         *cr,
                       gdouble          x,
@@ -1291,10 +1034,9 @@ gtk_do_render_handle (GtkStyleContext *context,
                       gdouble          width,
                       gdouble          height)
 {
-  const GdkRGBA *bg_color;
-  GdkRGBA lighter, darker;
-  GtkJunctionSides sides;
-  gint xx, yy;
+  GtkCssImageBuiltinType type;
+  GtkBorderStyle border_style;
+  gint border_width;
 
   gtk_render_background (context, cr, x, y, width, height);
   gtk_render_frame (context, cr, x, y, width, height);
@@ -1302,282 +1044,43 @@ gtk_do_render_handle (GtkStyleContext *context,
   if (render_icon_image (context, cr, x, y, width, height))
     return;
 
-  cairo_save (cr);
-
-  cairo_set_line_width (cr, 1.0);
-  sides = gtk_style_context_get_junction_sides (context);
-  bg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR));
-
-  color_shade (bg_color, 0.7, &darker);
-  color_shade (bg_color, 1.3, &lighter);
-
-  if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_GRIP))
+  border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
+  if (border_style == GTK_BORDER_STYLE_SOLID)
     {
-      /* reduce confusing values to a meaningful state */
-      if ((sides & (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT)) == 
(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT))
-        sides &= ~GTK_JUNCTION_CORNER_TOPLEFT;
-
-      if ((sides & (GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT)) == 
(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT))
-        sides &= ~GTK_JUNCTION_CORNER_TOPRIGHT;
-
-      if (sides == 0)
-        sides = GTK_JUNCTION_CORNER_BOTTOMRIGHT;
-
-      /* align drawing area to the connected side */
-      if (sides == GTK_JUNCTION_LEFT)
-        {
-          if (height < width)
-            width = height;
-        }
-      else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
-        {
-          if (width < height)
-            height = width;
-          else if (height < width)
-            width = height;
-        }
-      else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
-        {
-          /* make it square, aligning to bottom left */
-          if (width < height)
-            {
-              y += (height - width);
-              height = width;
-            }
-          else if (height < width)
-            width = height;
-        }
-      else if (sides == GTK_JUNCTION_RIGHT)
-        {
-          /* aligning to right */
-          if (height < width)
-            {
-              x += (width - height);
-              width = height;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
-        {
-          if (width < height)
-            height = width;
-          else if (height < width)
-            {
-              x += (width - height);
-              width = height;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
-        {
-          /* make it square, aligning to bottom right */
-          if (width < height)
-            {
-              y += (height - width);
-              height = width;
-            }
-          else if (height < width)
-            {
-              x += (width - height);
-              width = height;
-            }
-        }
-      else if (sides == GTK_JUNCTION_TOP)
-        {
-          if (width < height)
-            height = width;
-        }
-      else if (sides == GTK_JUNCTION_BOTTOM)
-        {
-          /* align to bottom */
-          if (width < height)
-            {
-              y += (height - width);
-              height = width;
-            }
-        }
-      else
-        g_assert_not_reached ();
-
-      if (sides == GTK_JUNCTION_LEFT ||
-          sides == GTK_JUNCTION_RIGHT)
-        {
-          gint xi;
-
-          xi = x;
-
-          while (xi < x + width)
-            {
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, x, y, x, y + height);
-              cairo_stroke (cr);
-              xi++;
-
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, xi, y, xi, y + height);
-              cairo_stroke (cr);
-              xi += 2;
-            }
-        }
-      else if (sides == GTK_JUNCTION_TOP ||
-               sides == GTK_JUNCTION_BOTTOM)
-        {
-          gint yi;
-
-          yi = y;
-
-          while (yi < y + height)
-            {
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, x, yi, x + width, yi);
-              cairo_stroke (cr);
-              yi++;
-
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, x, yi, x + width, yi);
-              cairo_stroke (cr);
-              yi += 2;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
-        {
-          gint xi, yi;
-
-          xi = x + width;
-          yi = y + height;
-
-          while (xi > x + 3)
-            {
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, xi, y, x, yi);
-              cairo_stroke (cr);
-
-              --xi;
-              --yi;
-
-              add_path_line (cr, xi, y, x, yi);
-              cairo_stroke (cr);
-
-              --xi;
-              --yi;
-
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, xi, y, x, yi);
-              cairo_stroke (cr);
-
-              xi -= 3;
-              yi -= 3;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
-        {
-          gint xi, yi;
-
-          xi = x;
-          yi = y + height;
-
-          while (xi < (x + width - 3))
-            {
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, xi, y, x + width, yi);
-              cairo_stroke (cr);
-
-              ++xi;
-              --yi;
+      GtkBorder border;
 
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, xi, y, x + width, yi);
-              cairo_stroke (cr);
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
 
-              ++xi;
-              --yi;
-
-              add_path_line (cr, xi, y, x + width, yi);
-              cairo_stroke (cr);
-
-              xi += 3;
-              yi -= 3;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
-        {
-          gint xi, yi;
-
-          xi = x + width;
-          yi = y;
-
-          while (xi > x + 3)
-            {
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, x, yi, xi, y + height);
-              cairo_stroke (cr);
-
-              --xi;
-              ++yi;
-
-              add_path_line (cr, x, yi, xi, y + height);
-              cairo_stroke (cr);
-
-              --xi;
-              ++yi;
-
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, x, yi, xi, y + height);
-              cairo_stroke (cr);
-
-              xi -= 3;
-              yi += 3;
-            }
-        }
-      else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
-        {
-          gint xi, yi;
-
-          xi = x;
-          yi = y;
-
-          while (xi < (x + width - 3))
-            {
-              gdk_cairo_set_source_rgba (cr, &lighter);
-              add_path_line (cr, xi, y + height, x + width, yi);
-              cairo_stroke (cr);
-
-              ++xi;
-              ++yi;
-
-              gdk_cairo_set_source_rgba (cr, &darker);
-              add_path_line (cr, xi, y + height, x + width, yi);
-              cairo_stroke (cr);
-
-              ++xi;
-              ++yi;
-
-              add_path_line (cr, xi, y + height, x + width, yi);
-              cairo_stroke (cr);
-
-              xi += 3;
-              yi += 3;
-            }
-        }
-    }
-  else if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_PANE_SEPARATOR))
-    {
-      if (width > height)
-        for (xx = x + width / 2 - 15; xx <= x + width / 2 + 15; xx += 5)
-          render_dot (cr, &lighter, &darker, xx, y + height / 2 - 1, 3);
-      else
-        for (yy = y + height / 2 - 15; yy <= y + height / 2 + 15; yy += 5)
-          render_dot (cr, &lighter, &darker, x + width / 2 - 1, yy, 3);
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
     }
   else
     {
-      for (yy = y; yy < y + height; yy += 3)
-        for (xx = x; xx < x + width; xx += 6)
-          {
-            render_dot (cr, &lighter, &darker, xx, yy, 2);
-            render_dot (cr, &lighter, &darker, xx + 3, yy + 1, 2);
-          }
+      border_width = 0;
     }
 
-  cairo_restore (cr);
+  cairo_translate (cr, x, y);
+
+  if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_GRIP))
+    type = GTK_CSS_IMAGE_BUILTIN_GRIP;
+  else if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_PANE_SEPARATOR))
+    type = GTK_CSS_IMAGE_BUILTIN_PANE_SEPARATOR;
+  else
+    type = GTK_CSS_IMAGE_BUILTIN_HANDLE;
+
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              width, height,
+                              type,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**
@@ -1672,35 +1175,6 @@ gtk_render_paint_spinner (cairo_t *cr,
 }
 
 static void
-render_spinner (GtkStyleContext *context,
-                cairo_t         *cr,
-                gdouble          x,
-                gdouble          y,
-                gdouble          width,
-                gdouble          height)
-{
-  const GdkRGBA *color;
-  gdouble radius;
-
-  radius = MIN (width / 2, height / 2);
-
-  color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR));
-
-  cairo_save (cr);
-  cairo_translate (cr, x + width / 2, y + height / 2);
-
-  _gtk_css_shadows_value_paint_spinner (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SHADOW),
-                                        cr,
-                                        radius,
-                                        -1);
-
-  gdk_cairo_set_source_rgba (cr, color);
-  gtk_render_paint_spinner (cr, radius, -1);
-
-  cairo_restore (cr);
-}
-
-static void
 gtk_do_render_activity (GtkStyleContext *context,
                         cairo_t         *cr,
                         gdouble          x,
@@ -1708,10 +1182,42 @@ gtk_do_render_activity (GtkStyleContext *context,
                         gdouble          width,
                         gdouble          height)
 {
+  GtkBorderStyle border_style;
+  gint border_width;
+
   if (render_icon_image (context, cr, x, y, width, height))
     return;
 
-  render_spinner (context, cr, x, y, width, height);
+  border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
+  if (border_style == GTK_BORDER_STYLE_SOLID)
+    {
+      GtkBorder border;
+
+      border.top = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
+      border.right = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
+      border.bottom = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
+      border.left = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
+
+      border_width = MIN (MIN (border.top, border.bottom),
+                          MIN (border.left, border.right));
+    }
+  else
+    {
+      border_width = 0;
+    }
+
+  cairo_translate (cr, x, y);
+
+  gtk_css_image_builtin_draw (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_ICON_SOURCE)),
+                              cr,
+                              width, height,
+                              GTK_CSS_IMAGE_BUILTIN_SPINNER,
+                              gtk_style_context_get_state (context),
+                              gtk_style_context_get_junction_sides (context),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)),
+                              _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BORDER_TOP_COLOR)),
+                              border_width);
 }
 
 /**


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