[gnome-shell] Move rendering into st-theme-node-drawing.c
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Move rendering into st-theme-node-drawing.c
- Date: Wed, 24 Mar 2010 18:13:55 +0000 (UTC)
commit 5060081db5fb0a5848dd04d7723ed3f5d02c1668
Author: Colin Walters <walters verbum org>
Date: Mon Feb 8 13:40:25 2010 -0500
Move rendering into st-theme-node-drawing.c
The idea behind this move is that we have a lot more control over
rendering if StWidget isn't a big pile of actors, and things are
more efficient.
https://bugzilla.gnome.org/show_bug.cgi?id=607500
src/Makefile-st.am | 8 +-
src/st/st-button.c | 1 -
src/st/st-shadow-texture.c | 273 ----------
src/st/st-shadow-texture.h | 30 --
src/st/st-texture-frame.c | 621 -----------------------
src/st/st-texture-frame.h | 94 ----
src/st/st-theme-node-drawing.c | 1097 ++++++++++++++++++++++++++++++++++++++++
src/st/st-theme-node-private.h | 86 ++++
src/st/st-theme-node.c | 109 +---
src/st/st-theme-node.h | 5 +
src/st/st-widget.c | 645 +-----------------------
11 files changed, 1231 insertions(+), 1738 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index 706c588..6b06688 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -83,13 +83,11 @@ st_source_h = \
st/st-scrollable.h \
st/st-scroll-bar.h \
st/st-scroll-view.h \
- st/st-shadow-texture.h \
st/st-shadow.h \
st/st-subtexture.h \
st/st-table.h \
st/st-table-child.h \
st/st-texture-cache.h \
- st/st-texture-frame.h \
st/st-theme.h \
st/st-theme-context.h \
st/st-theme-node.h \
@@ -109,7 +107,8 @@ BUILT_SOURCES += st.h
st_source_private_h = \
st/st-private.h \
st/st-table-private.h \
- st/st-theme-private.h
+ st/st-theme-private.h \
+ st/st-theme-node-private.h
# please, keep this sorted alphabetically
st_source_c = \
@@ -130,16 +129,15 @@ st_source_c = \
st/st-scrollable.c \
st/st-scroll-bar.c \
st/st-scroll-view.c \
- st/st-shadow-texture.c \
st/st-shadow.c \
st/st-subtexture.c \
st/st-table.c \
st/st-table-child.c \
st/st-texture-cache.c \
- st/st-texture-frame.c \
st/st-theme.c \
st/st-theme-context.c \
st/st-theme-node.c \
+ st/st-theme-node-drawing.c \
st/st-tooltip.c \
st/st-widget.c \
$(NULL)
diff --git a/src/st/st-button.c b/src/st/st-button.c
index 2b8d757..7fbc101 100644
--- a/src/st/st-button.c
+++ b/src/st/st-button.c
@@ -45,7 +45,6 @@
#include "st-button.h"
#include "st-marshal.h"
-#include "st-texture-frame.h"
#include "st-texture-cache.h"
#include "st-private.h"
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
new file mode 100644
index 0000000..374a55c
--- /dev/null
+++ b/src/st/st-theme-node-drawing.c
@@ -0,0 +1,1097 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* Drawing for StWidget.
+
+ Copyright (C) 2009,2010 Red Hat, Inc.
+
+ Contains code derived from:
+ rectangle.c: Rounded rectangle.
+ Copyright (C) 2008 litl, LLC.
+ st-shadow-texture.c: a class for creating soft shadow texture
+ Copyright (C) 2009 Florian Müllner <fmuellner src gnome org>
+ st-texture-frame.h: Expandible texture actor
+ Copyright 2007 OpenedHand
+ Copyright 2009 Intel Corporation.
+
+ The St is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The St 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the St; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "st-theme-private.h"
+#include "st-theme-context.h"
+#include "st-texture-cache.h"
+#include "st-theme-node-private.h"
+
+/*****
+ * Shadows
+ *****/
+
+static gdouble *
+calculate_gaussian_kernel (gdouble sigma,
+ guint n_values)
+{
+ gdouble *ret, sum;
+ gdouble exp_divisor;
+ gint half, i;
+
+ g_return_val_if_fail ((int) sigma > 0, NULL);
+
+ half = n_values / 2;
+
+ ret = g_malloc (n_values * sizeof (gdouble));
+ sum = 0.0;
+
+ exp_divisor = 2 * sigma * sigma;
+
+ /* n_values of 1D Gauss function */
+ for (i = 0; i < n_values; i++)
+ {
+ ret[i] = exp (-(i - half) * (i - half) / exp_divisor);
+ sum += ret[i];
+ }
+
+ /* normalize */
+ for (i = 0; i < n_values; i++)
+ ret[i] /= sum;
+
+ return ret;
+}
+
+static CoglHandle
+create_shadow_material (StThemeNode *node,
+ CoglHandle src_texture)
+{
+ CoglColor color;
+ CoglHandle material;
+ CoglHandle texture;
+ StShadow *shadow_spec;
+ guchar *pixels_in, *pixels_out;
+ gint width_in, height_in, rowstride_in;
+ gint width_out, height_out, rowstride_out;
+ float sigma;
+
+ shadow_spec = st_theme_node_get_shadow (node);
+ if (!shadow_spec)
+ return COGL_INVALID_HANDLE;
+
+ /* we use an approximation of the sigma - blur radius relationship used
+ in Firefox for doing SVG blurs; see
+ http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
+ */
+ sigma = shadow_spec->blur / 1.9;
+
+ width_in = cogl_texture_get_width (src_texture);
+ height_in = cogl_texture_get_height (src_texture);
+ rowstride_in = (width_in + 3) & ~3;
+
+ pixels_in = g_malloc0 (rowstride_in * height_in);
+
+ cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
+ rowstride_in, pixels_in);
+
+ if ((guint) shadow_spec->blur == 0)
+ {
+ width_out = width_in;
+ height_out = height_in;
+ rowstride_out = rowstride_in;
+ pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
+ }
+ else
+ {
+ gdouble *kernel;
+ guchar *line;
+ gint n_values, half;
+ gint x_in, y_in, x_out, y_out, i;
+
+ n_values = (gint) 5 * sigma;
+ half = n_values / 2;
+
+ width_out = width_in + 2 * half;
+ height_out = height_in + 2 * half;
+ rowstride_out = (width_out + 3) & ~3;
+
+ pixels_out = g_malloc0 (rowstride_out * height_out);
+ line = g_malloc0 (rowstride_out);
+
+ kernel = calculate_gaussian_kernel (sigma, n_values);
+
+ /* vertical blur */
+ for (x_in = 0; x_in < width_in; x_in++)
+ for (y_out = 0; y_out < height_out; y_out++)
+ {
+ guchar *pixel_in, *pixel_out;
+ gint i0, i1;
+
+ y_in = y_out - half;
+
+ /* We read from the source at 'y = y_in + i - half'; clamp the
+ * full i range [0, n_values) so that y is in [0, height_in).
+ */
+ i0 = MAX (half - y_in, 0);
+ i1 = MIN (height_in + half - y_in, n_values);
+
+ pixel_in = pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
+ pixel_out = pixels_out + y_out * rowstride_out + (x_in + half);
+
+ for (i = i0; i < i1; i++)
+ {
+ *pixel_out += *pixel_in * kernel[i];
+ pixel_in += rowstride_in;
+ }
+ }
+
+ /* horizontal blur */
+ for (y_out = 0; y_out < height_out; y_out++)
+ {
+ memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
+
+ for (x_out = 0; x_out < width_out; x_out++)
+ {
+ gint i0, i1;
+ guchar *pixel_out, *pixel_in;
+
+ /* We read from the source at 'x = x_out + i - half'; clamp the
+ * full i range [0, n_values) so that x is in [0, width_out).
+ */
+ i0 = MAX (half - x_out, 0);
+ i1 = MIN (width_out + half - x_out, n_values);
+
+ pixel_in = line + x_out + i0 - half;
+ pixel_out = pixels_out + rowstride_out * y_out + x_out;
+
+ *pixel_out = 0;
+ for (i = i0; i < i1; i++)
+ {
+ *pixel_out += *pixel_in * kernel[i];
+ pixel_in++;
+ }
+ }
+ }
+ g_free (kernel);
+ g_free (line);
+ }
+
+ texture = cogl_texture_new_from_data (width_out,
+ height_out,
+ COGL_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_A_8,
+ COGL_PIXEL_FORMAT_A_8,
+ rowstride_out,
+ pixels_out);
+
+ g_free (pixels_in);
+ g_free (pixels_out);
+
+ material = cogl_material_new ();
+
+ cogl_color_set_from_4ub (&color,
+ shadow_spec->color.red, shadow_spec->color.green,
+ shadow_spec->color.blue, shadow_spec->color.alpha);
+ cogl_color_premultiply (&color);
+
+ cogl_material_set_layer_combine_constant (material, 0, &color);
+ cogl_material_set_layer (material, 0, texture);
+
+ /* We ignore the material color, which encodes the overall opacity of the
+ * actor, so setting an ancestor of the shadow to partially opaque won't
+ * work. The easiest way to fix this would be to not set the combine or constant color
+ * here, then in paint set the material color to the shadow_spec_color *
+ * paint_opacity.*/
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA = MODULATE (CONSTANT, TEXTURE[A])",
+ NULL);
+
+
+ cogl_handle_unref (texture);
+
+ return material;
+}
+
+
+/****
+ * Rounded corners
+ ****/
+
+typedef struct {
+ ClutterColor color;
+ ClutterColor border_color_1;
+ ClutterColor border_color_2;
+ guint radius;
+ guint border_width_1;
+ guint border_width_2;
+} StCornerSpec;
+
+static CoglHandle
+create_corner_texture (StCornerSpec *corner)
+{
+ CoglHandle texture;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ guint rowstride;
+ guint8 *data;
+ guint size;
+ guint max_border_width;
+
+ max_border_width = MAX(corner->border_width_2, corner->border_width_1);
+ size = 2 * MAX(max_border_width, corner->radius);
+ rowstride = size * 4;
+ data = g_new0 (guint8, size * rowstride);
+
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ size, size,
+ rowstride);
+ cr = cairo_create (surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_scale (cr, size, size);
+
+ /* TODO support nonuniform border widths */
+
+ if (corner->border_width_1 < corner->radius)
+ {
+ double internal_radius = 0.5 * (1.0 - (double) corner->border_width_1 / corner->radius);
+
+ if (corner->border_width_1 != 0)
+ {
+ cairo_set_source_rgba (cr,
+ corner->border_color_1.red / 255.,
+ corner->border_color_1.green / 255.,
+ corner->border_color_1.blue / 255.,
+ corner->border_color_1.alpha / 255.);
+
+ cairo_arc (cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
+ cairo_fill (cr);
+ }
+
+ cairo_set_source_rgba (cr,
+ corner->color.red / 255.,
+ corner->color.green / 255.,
+ corner->color.blue / 255.,
+ corner->color.alpha / 255.);
+ cairo_arc (cr, 0.5, 0.5, internal_radius, 0, 2 * M_PI);
+ cairo_fill (cr);
+ }
+ else
+ {
+ double radius;
+
+ radius = (gdouble)corner->radius / corner->border_width_1;
+
+ cairo_set_source_rgba (cr,
+ corner->border_color_1.red / 255.,
+ corner->border_color_1.green / 255.,
+ corner->border_color_1.blue / 255.,
+ corner->border_color_1.alpha / 255.);
+
+ cairo_arc (cr, radius, radius, radius, M_PI, 3 * M_PI / 2);
+ cairo_line_to (cr, 1.0 - radius, 0.0);
+ cairo_arc (cr, 1.0 - radius, radius, radius, 3 * M_PI / 2, 2 * M_PI);
+ cairo_line_to (cr, 1.0, 1.0 - radius);
+ cairo_arc (cr, 1.0 - radius, 1.0 - radius, radius, 0, M_PI / 2);
+ cairo_line_to (cr, radius, 1.0);
+ cairo_arc (cr, radius, 1.0 - radius, radius, M_PI / 2, M_PI);
+ cairo_fill (cr);
+ }
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (surface);
+
+ texture = cogl_texture_new_from_data (size, size,
+ COGL_TEXTURE_NONE,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ COGL_PIXEL_FORMAT_BGRA_8888_PRE,
+#else
+ COGL_PIXEL_FORMAT_ARGB_8888_PRE,
+#endif
+ COGL_PIXEL_FORMAT_ANY,
+ rowstride,
+ data);
+ g_free (data);
+ g_assert (texture != COGL_INVALID_HANDLE);
+
+ return texture;
+}
+
+static char *
+corner_to_string (StCornerSpec *corner)
+{
+ return g_strdup_printf ("st-theme-node-corner:%02x%02x%02x%02x,%02x%02x%02x%02x,%02x%02x%02x%02x,%u,%u,%u",
+ corner->color.red, corner->color.blue, corner->color.green, corner->color.alpha,
+ corner->border_color_1.red, corner->border_color_1.green, corner->border_color_1.blue, corner->border_color_1.alpha,
+ corner->border_color_2.red, corner->border_color_2.green, corner->border_color_2.blue, corner->border_color_2.alpha,
+ corner->radius,
+ corner->border_width_1,
+ corner->border_width_2);
+}
+
+typedef struct {
+ StThemeNode *node;
+ StCornerSpec *corner;
+} LoadCornerData;
+
+static CoglHandle
+load_corner (StTextureCache *cache,
+ const char *key,
+ void *datap,
+ GError **error)
+{
+ LoadCornerData *data = datap;
+
+ return create_corner_texture (data->corner);
+}
+
+/* To match the CSS specification, we want the border to look like it was
+ * drawn over the background. But actually drawing the border over the
+ * background will produce slightly bad antialiasing at the edges, so
+ * compute the effective border color instead.
+ */
+#define NORM(x) (t = (x) + 127, (t + (t >> 8)) >> 8)
+#define MULT(c,a) NORM(c*a)
+
+static void
+premultiply (ClutterColor *color)
+{
+ guint t;
+ color->red = MULT (color->red, color->alpha);
+ color->green = MULT (color->green, color->alpha);
+ color->blue = MULT (color->blue, color->alpha);
+}
+
+static void
+unpremultiply (ClutterColor *color)
+{
+ if (color->alpha != 0)
+ {
+ color->red = (color->red * 255 + 127) / color->alpha;
+ color->green = (color->green * 255 + 127) / color->alpha;
+ color->blue = (color->blue * 255 + 127) / color->alpha;
+ }
+}
+
+static void
+over (const ClutterColor *source,
+ const ClutterColor *destination,
+ ClutterColor *result)
+{
+ guint t;
+ ClutterColor src = *source;
+ ClutterColor dst = *destination;
+
+ premultiply (&src);
+ premultiply (&dst);
+
+ result->alpha = src.alpha + NORM ((255 - src.alpha) * dst.alpha);
+ result->red = src.red + NORM ((255 - src.alpha) * dst.red);
+ result->green = src.green + NORM ((255 - src.alpha) * dst.green);
+ result->blue = src.blue + NORM ((255 - src.alpha) * dst.blue);
+
+ unpremultiply (result);
+}
+
+static CoglHandle
+st_theme_node_lookup_corner (StThemeNode *node,
+ StCorner corner_id)
+{
+ CoglHandle texture;
+ char *key;
+ StTextureCache *cache;
+ StCornerSpec corner;
+ LoadCornerData data;
+
+ if (node->border_radius[corner_id] == 0)
+ return COGL_INVALID_HANDLE;
+
+ cache = st_texture_cache_get_default ();
+
+ corner.radius = node->border_radius[corner_id];
+ corner.color = node->background_color;
+
+ switch (corner_id)
+ {
+ case ST_CORNER_TOPLEFT:
+ corner.border_width_1 = node->border_width[ST_SIDE_TOP];
+ corner.border_width_2 = node->border_width[ST_SIDE_LEFT];
+ over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1);
+ over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2);
+ break;
+ case ST_CORNER_TOPRIGHT:
+ corner.border_width_1 = node->border_width[ST_SIDE_TOP];
+ corner.border_width_2 = node->border_width[ST_SIDE_RIGHT];
+ over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1);
+ over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2);
+ break;
+ case ST_CORNER_BOTTOMRIGHT:
+ corner.border_width_1 = node->border_width[ST_SIDE_BOTTOM];
+ corner.border_width_2 = node->border_width[ST_SIDE_RIGHT];
+ over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1);
+ over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2);
+ break;
+ case ST_CORNER_BOTTOMLEFT:
+ corner.border_width_1 = node->border_width[ST_SIDE_BOTTOM];
+ corner.border_width_2 = node->border_width[ST_SIDE_LEFT];
+ over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1);
+ over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2);
+ break;
+ }
+
+ key = corner_to_string (&corner);
+
+ data.node = node;
+ data.corner = &corner;
+ texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &data, NULL);
+
+ g_free (key);
+
+ return texture;
+}
+
+static void
+get_background_position (StThemeNode *self,
+ const ClutterActorBox *allocation,
+ ClutterActorBox *result)
+{
+ gfloat w, h;
+
+ result->x1 = result->y1 = 0;
+ result->x2 = allocation->x2 - allocation->x1;
+ result->y2 = allocation->y2 - allocation->y1;
+
+ w = cogl_texture_get_width (self->background_texture);
+ h = cogl_texture_get_height (self->background_texture);
+
+ /* scale the background into the allocated bounds */
+ if (w > result->x2 || h > result->y2)
+ {
+ gint new_h, new_w, offset;
+ gint box_w, box_h;
+
+ box_w = (int) result->x2;
+ box_h = (int) result->y2;
+
+ /* scale to fit */
+ new_h = (int)((h / w) * ((gfloat) box_w));
+ new_w = (int)((w / h) * ((gfloat) box_h));
+
+ if (new_h > box_h)
+ {
+ /* center for new width */
+ offset = ((box_w) - new_w) * 0.5;
+ result->x1 = offset;
+ result->x2 = offset + new_w;
+
+ result->y2 = box_h;
+ }
+ else
+ {
+ /* center for new height */
+ offset = ((box_h) - new_h) * 0.5;
+ result->y1 = offset;
+ result->y2 = offset + new_h;
+
+ result->x2 = box_w;
+ }
+ }
+ else
+ {
+ /* center the background on the widget */
+ result->x1 = (int)(((allocation->x2 - allocation->x1) / 2) - (w / 2));
+ result->y1 = (int)(((allocation->y2 - allocation->y1) / 2) - (h / 2));
+ result->x2 = result->x1 + w;
+ result->y2 = result->y1 + h;
+ }
+}
+
+/* Use of this function marks code which doesn't support
+ * non-uniform widths and/or colors.
+ */
+static gboolean
+get_arbitrary_border (StThemeNode *node,
+ int *width,
+ ClutterColor *color)
+{
+ int w;
+
+ w = st_theme_node_get_border_width (node, ST_SIDE_TOP);
+ if (w > 0)
+ {
+ if (width)
+ *width = w;
+ if (color)
+ st_theme_node_get_border_color (node, ST_SIDE_TOP, color);
+ return TRUE;
+ }
+
+ if (width)
+ *width = 0;
+ return FALSE;
+}
+
+static CoglHandle
+st_theme_node_render_gradient (StThemeNode *node)
+{
+ CoglHandle texture;
+ int radius[4], i;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ gboolean round_border = FALSE;
+ ClutterColor border_color;
+ int border_width;
+ guint rowstride;
+ guchar *data;
+
+ rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, node->alloc_width);
+ data = g_new0 (guchar, node->alloc_height * rowstride);
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ node->alloc_width,
+ node->alloc_height,
+ rowstride);
+ cr = cairo_create (surface);
+
+ /* TODO - support non-uniform border colors and widths */
+ get_arbitrary_border (node, &border_width, &border_color);
+
+ for (i = 0; i < 4; i++)
+ {
+ radius[i] = st_theme_node_get_border_radius (node, i);
+ if (radius[i] > 0)
+ round_border = TRUE;
+ }
+
+ if (node->background_gradient_type == ST_GRADIENT_VERTICAL)
+ pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height);
+ else if (node->background_gradient_type == ST_GRADIENT_HORIZONTAL)
+ pattern = cairo_pattern_create_linear (0, 0, node->alloc_width, 0);
+ else
+ {
+ gdouble cx, cy;
+
+ cx = node->alloc_width / 2.;
+ cy = node->alloc_height / 2.;
+ pattern = cairo_pattern_create_radial (cx, cy, 0, cx, cy, MIN (cx, cy));
+ }
+
+ cairo_pattern_add_color_stop_rgba (pattern, 0,
+ node->background_color.red / 255.,
+ node->background_color.green / 255.,
+ node->background_color.blue / 255.,
+ node->background_color.alpha / 255.);
+ cairo_pattern_add_color_stop_rgba (pattern, 1,
+ node->background_gradient_end.red / 255.,
+ node->background_gradient_end.green / 255.,
+ node->background_gradient_end.blue / 255.,
+ node->background_gradient_end.alpha / 255.);
+
+ if (round_border)
+ {
+ if (radius[ST_CORNER_TOPLEFT] > 0)
+ cairo_arc (cr,
+ radius[ST_CORNER_TOPLEFT],
+ radius[ST_CORNER_TOPLEFT],
+ radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
+ else
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
+ if (radius[ST_CORNER_TOPRIGHT] > 0)
+ cairo_arc (cr,
+ node->alloc_width - radius[ST_CORNER_TOPRIGHT],
+ radius[ST_CORNER_TOPRIGHT],
+ radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
+ cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
+ if (radius[ST_CORNER_BOTTOMRIGHT])
+ cairo_arc (cr,
+ node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
+ node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
+ radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
+ cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
+ if (radius[ST_CORNER_BOTTOMLEFT])
+ cairo_arc (cr,
+ radius[ST_CORNER_BOTTOMLEFT],
+ node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
+ radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
+ cairo_close_path (cr);
+ }
+ else
+ cairo_rectangle (cr, 0, 0, node->alloc_width, node->alloc_height);
+
+ if (border_width > 0)
+ {
+ cairo_path_t *path;
+
+ path = cairo_copy_path (cr);
+ cairo_set_source_rgba (cr,
+ border_color.red / 255.,
+ border_color.green / 255.,
+ border_color.blue / 255.,
+ border_color.alpha / 255.);
+ cairo_fill (cr);
+
+ cairo_translate (cr, border_width, border_width);
+ cairo_scale (cr,
+ (gdouble)(node->alloc_width - 2 * border_width) / node->alloc_width,
+ (gdouble)(node->alloc_height - 2 * border_width) / node->alloc_height);
+ cairo_append_path (cr, path);
+ cairo_path_destroy (path);
+ }
+
+ cairo_set_source (cr, pattern);
+ cairo_fill (cr);
+
+ cairo_pattern_destroy (pattern);
+
+ texture = cogl_texture_new_from_data (node->alloc_width, node->alloc_height,
+ COGL_TEXTURE_NONE,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ COGL_PIXEL_FORMAT_ARGB_8888_PRE,
+#else
+ COGL_PIXEL_FORMAT_ANY,
+#error unknown endianness type
+#endif
+ COGL_PIXEL_FORMAT_ANY,
+ rowstride,
+ data);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ g_free (data);
+
+ return texture;
+}
+
+void
+_st_theme_node_free_drawing_state (StThemeNode *node)
+{
+ if (node->background_texture != COGL_INVALID_HANDLE)
+ cogl_handle_unref (node->background_texture);
+ if (node->shadow_material != COGL_INVALID_HANDLE)
+ cogl_handle_unref (node->shadow_material);
+ if (node->border_texture != COGL_INVALID_HANDLE)
+ cogl_handle_unref (node->border_texture);
+
+ _st_theme_node_init_drawing_state (node);
+}
+
+void
+_st_theme_node_init_drawing_state (StThemeNode *node)
+{
+ node->background_texture = COGL_INVALID_HANDLE;
+ node->shadow_material = COGL_INVALID_HANDLE;
+ node->border_texture = COGL_INVALID_HANDLE;
+}
+
+static void
+st_theme_node_render_resources (StThemeNode *node,
+ float width,
+ float height)
+{
+ StTextureCache *texture_cache;
+ StBorderImage *border_image;
+ const char *background_image;
+
+ texture_cache = st_texture_cache_get_default ();
+
+ /* FIXME - need to separate this into things that need to be recomputed on
+ * geometry change versus things that can be cached regardless, such as
+ * a background image.
+ */
+ _st_theme_node_free_drawing_state (node);
+
+ node->alloc_width = width;
+ node->alloc_height = height;
+
+ _st_theme_node_ensure_background (node);
+ _st_theme_node_ensure_geometry (node);
+
+ /* Load referenced images from disk and draw anything we need with cairo now */
+
+ border_image = st_theme_node_get_border_image (node);
+ if (border_image)
+ {
+ const char *filename;
+
+ filename = st_border_image_get_filename (border_image);
+
+ node->border_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, filename);
+ }
+ else if (node->background_gradient_type != ST_GRADIENT_NONE)
+ {
+ node->border_texture = st_theme_node_render_gradient (node);
+ }
+
+ background_image = st_theme_node_get_background_image (node);
+ if (background_image != NULL)
+ {
+ StShadow *shadow_spec;
+
+ node->background_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, background_image);
+
+ shadow_spec = st_theme_node_get_shadow (node);
+ if (shadow_spec)
+ {
+ node->shadow_material = create_shadow_material (node, node->background_texture);
+ }
+ }
+
+ node->corner_texture = st_theme_node_lookup_corner (node, ST_CORNER_TOPLEFT);
+}
+
+static void
+paint_texture_with_opacity (CoglHandle texture,
+ ClutterActorBox *box,
+ guint8 paint_opacity)
+{
+ if (paint_opacity == 255)
+ {
+ /* Minor: optimization use the default material if we can */
+ cogl_set_source_texture (texture);
+ cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
+ return;
+ }
+
+ CoglHandle material;
+
+ material = cogl_material_new ();
+ cogl_material_set_layer (material, 0, texture);
+ cogl_material_set_color4ub (material,
+ paint_opacity, paint_opacity, paint_opacity, paint_opacity);
+
+ cogl_set_source (material);
+ cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
+
+ cogl_handle_unref (material);
+}
+
+static void
+st_theme_node_paint_borders (StThemeNode *node,
+ const ClutterActorBox *box,
+ guint8 paint_opacity)
+
+{
+ float width, height;
+ int border_width;
+ int border_radius;
+ int max_width_radius;
+ ClutterColor border_color;
+ CoglHandle material;
+
+ width = box->x2 - box->x1;
+ height = box->y2 - box->y1;
+
+ get_arbitrary_border (node, &border_width, &border_color);
+ border_radius = node->border_radius[ST_CORNER_TOPLEFT];
+
+ max_width_radius = MAX(border_width, border_radius);
+
+ /* borders */
+ if (border_width > 0)
+ {
+ ClutterColor effective_border;
+
+ over (&border_color, &node->background_color, &effective_border);
+
+ cogl_set_source_color4ub (effective_border.red,
+ effective_border.green,
+ effective_border.blue,
+ paint_opacity * effective_border.alpha / 255);
+
+ if (border_radius > 0) /* skip corners */
+ {
+ /* NORTH */
+ cogl_rectangle (max_width_radius, 0,
+ width - max_width_radius, border_width);
+
+ /* EAST */
+ cogl_rectangle (width - border_width, max_width_radius,
+ width, height - max_width_radius);
+
+ /* SOUTH */
+ cogl_rectangle (max_width_radius, height - border_width,
+ width - max_width_radius, height);
+
+ /* WEST */
+ cogl_rectangle (0, max_width_radius,
+ border_width, height - max_width_radius);
+ }
+ else /* include corners */
+ {
+ /* NORTH */
+ cogl_rectangle (0, 0,
+ width, border_width);
+
+ /* EAST */
+ cogl_rectangle (width - border_width, border_width,
+ width, height - border_width);
+
+ /* SOUTH */
+ cogl_rectangle (0, height - border_width,
+ width, height);
+
+ /* WEST */
+ cogl_rectangle (0, border_width,
+ border_width, height - border_width);
+ }
+ }
+
+ /* corners */
+ if (node->corner_texture != COGL_INVALID_HANDLE)
+ {
+ material = cogl_material_new ();
+ cogl_material_set_layer (material, 0, node->corner_texture);
+ cogl_material_set_color4ub (material,
+ paint_opacity, paint_opacity, paint_opacity, paint_opacity);
+
+ cogl_set_source (material);
+
+ cogl_rectangle_with_texture_coords (0, 0, max_width_radius, max_width_radius, 0, 0, 0.5, 0.5);
+ cogl_rectangle_with_texture_coords (width - max_width_radius, 0, width, max_width_radius, 0.5, 0, 1, 0.5);
+ cogl_rectangle_with_texture_coords (width - max_width_radius, height - max_width_radius, width, height, 0.5, 0.5, 1, 1);
+ cogl_rectangle_with_texture_coords (0, height - max_width_radius, max_width_radius, height, 0, 0.5, 0.5, 1);
+
+ cogl_handle_unref (material);
+ }
+
+ /* background color */
+ cogl_set_source_color4ub (node->background_color.red,
+ node->background_color.green,
+ node->background_color.blue,
+ paint_opacity * node->background_color.alpha / 255);
+
+ if (border_radius > border_width)
+ {
+ /* Once we've drawn the borders and corners, if the corners are bigger
+ * the the border width, the remaining area is shaped like
+ *
+ * ########
+ * ##########
+ * ##########
+ * ########
+ *
+ * We draw it in 3 pieces - first the top and bottom, then the main
+ * rectangle
+ */
+ cogl_rectangle (border_radius, border_width,
+ width - border_radius, border_radius);
+ cogl_rectangle (border_radius, height - border_radius,
+ width - border_radius, height - border_width);
+ }
+
+ cogl_rectangle (border_width, max_width_radius,
+ width - border_width, height - max_width_radius);
+}
+
+static void
+st_theme_node_paint_sliced_border_image (StThemeNode *node,
+ const ClutterActorBox *box,
+ guint8 paint_opacity)
+{
+ gfloat ex, ey;
+ gfloat tx1, ty1, tx2, ty2;
+ gint border_left, border_right, border_top, border_bottom;
+ float img_width, img_height;
+ StBorderImage *border_image;
+ CoglHandle material;
+
+ border_image = st_theme_node_get_border_image (node);
+ g_assert (border_image != NULL);
+
+ st_border_image_get_borders (border_image,
+ &border_left, &border_right, &border_top, &border_bottom);
+
+ img_width = cogl_texture_get_width (node->border_texture);
+ img_height = cogl_texture_get_height (node->border_texture);
+
+ tx1 = border_left / img_width;
+ tx2 = (img_width - border_right) / img_width;
+ ty1 = border_top / img_height;
+ ty2 = (img_height - border_bottom) / img_height;
+
+ ex = node->alloc_width - border_right;
+ if (ex < 0)
+ ex = border_right; /* FIXME ? */
+
+ ey = node->alloc_height - border_bottom;
+ if (ey < 0)
+ ey = border_bottom; /* FIXME ? */
+
+ material = cogl_material_new ();
+ cogl_material_set_layer (material, 0, node->border_texture);
+ cogl_material_set_color4ub (material,
+ paint_opacity, paint_opacity, paint_opacity, paint_opacity);
+
+ cogl_set_source (material);
+
+ {
+ GLfloat rectangles[] =
+ {
+ /* top left corner */
+ 0, 0, border_left, border_top,
+ 0.0, 0.0,
+ tx1, ty1,
+
+ /* top middle */
+ border_left, 0, ex, border_top,
+ tx1, 0.0,
+ tx2, ty1,
+
+ /* top right */
+ ex, 0, node->alloc_width, border_top,
+ tx2, 0.0,
+ 1.0, ty1,
+
+ /* mid left */
+ 0, border_top, border_left, ey,
+ 0.0, ty1,
+ tx1, ty2,
+
+ /* center */
+ border_left, border_top, ex, ey,
+ tx1, ty1,
+ tx2, ty2,
+
+ /* mid right */
+ ex, border_top, node->alloc_width, ey,
+ tx2, ty1,
+ 1.0, ty2,
+
+ /* bottom left */
+ 0, ey, border_left, node->alloc_height,
+ 0.0, ty2,
+ tx1, 1.0,
+
+ /* bottom center */
+ border_left, ey, ex, node->alloc_height,
+ tx1, ty2,
+ tx2, 1.0,
+
+ /* bottom right */
+ ex, ey, node->alloc_width, node->alloc_height,
+ tx2, ty2,
+ 1.0, 1.0
+ };
+
+ cogl_rectangles_with_texture_coords (rectangles, 9);
+ }
+
+ cogl_handle_unref (material);
+}
+
+void
+st_theme_node_paint (StThemeNode *node,
+ const ClutterActorBox *box,
+ guint8 paint_opacity)
+{
+ float width, height;
+ ClutterActorBox allocation;
+
+ /* Some things take an ActorBox, some things just width/height */
+ width = box->x2 - box->x1;
+ height = box->y2 - box->y1;
+ allocation.x1 = allocation.y1 = 0;
+ allocation.x2 = width;
+ allocation.y2 = height;
+
+ if (node->alloc_width != width || node->alloc_height != height)
+ st_theme_node_render_resources (node, width, height);
+
+ /* Rough notes about the relationship of borders and backgrounds in CSS3;
+ * see http://www.w3.org/TR/css3-background/ for more accurate details.
+ *
+ * - Things are drawn in 4 layers, from the bottom:
+ * Background color
+ * Background image
+ * Border color or border image
+ * Content
+ * - The background color, gradient and image extend to and are clipped by
+ * the edge of the border area, so will be rounded if the border is
+ * rounded. (CSS3 background-clip property modifies this)
+ * - The border image replaces what would normally be drawn by the border
+ * - The border image is not clipped by a rounded border-radius
+ * - The border radius rounds the background even if the border is
+ * zero width or a border image is being used.
+ *
+ * Deviations from the above as implemented here:
+ * - Nonuniform border widths combined with a non-zero border radius result
+ * in the border radius being ignored
+ * - The combination of border image and a non-zero border radius is
+ * not supported; the background color will be drawn with square
+ * corners.
+ * - The combination of border image and a background gradient is not
+ * supported; the background will be drawn as a solid color
+ * - The background image is drawn above the border color or image,
+ * not below it.
+ * - We don't clip the background image to the (rounded) border area.
+ *
+ * The first three allow us to always draw with no more than a single
+ * border_image and a single background image above it.
+ */
+
+ if (node->border_texture != COGL_INVALID_HANDLE)
+ {
+ /* Gradients and border images are mutually exclusive at this time */
+ if (node->background_gradient_type != ST_GRADIENT_NONE)
+ paint_texture_with_opacity (node->border_texture, &allocation, paint_opacity);
+ else
+ st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity);
+ }
+ else
+ st_theme_node_paint_borders (node, box, paint_opacity);
+
+ if (node->background_texture != COGL_INVALID_HANDLE)
+ {
+ ClutterActorBox background_box;
+
+ get_background_position (node, &allocation, &background_box);
+
+ /* CSS based drop shadows
+ *
+ * Drop shadows in ST are modelled after the CSS3 box-shadow property;
+ * see http://www.css3.info/preview/box-shadow/ for a detailed description.
+ *
+ * While the syntax of the property is mostly identical - we do not support
+ * multiple shadows and allow for a more liberal placement of the color
+ * parameter - its interpretation defers significantly in that the shadow's
+ * shape is not determined by the bounding box, but by the CSS background
+ * image (we could exend this in the future to take other CSS properties
+ * like boder and background color into account).
+ */
+ if (node->shadow_material != COGL_INVALID_HANDLE)
+ {
+ StShadow *shadow_spec;
+ ClutterActorBox shadow_box;
+
+ shadow_spec = node->shadow;
+
+ shadow_box.x1 = background_box.x1 + shadow_spec->xoffset - shadow_spec->blur;
+ shadow_box.y1 = background_box.y1 + shadow_spec->yoffset - shadow_spec->blur;
+ shadow_box.x2 = background_box.x2 + shadow_spec->xoffset + shadow_spec->blur;
+ shadow_box.y2 = background_box.y2 + shadow_spec->yoffset + shadow_spec->blur;
+
+ cogl_material_set_color4ub (node->shadow_material,
+ paint_opacity, paint_opacity, paint_opacity, paint_opacity);
+
+ cogl_set_source (node->shadow_material);
+ cogl_rectangle_with_texture_coords (shadow_box.x1, shadow_box.y1, shadow_box.x2, shadow_box.y2,
+ 0, 0, 1, 1);
+ }
+
+ paint_texture_with_opacity (node->background_texture, &background_box, paint_opacity);
+ }
+}
diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h
new file mode 100644
index 0000000..6074d5a
--- /dev/null
+++ b/src/st/st-theme-node-private.h
@@ -0,0 +1,86 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __ST_THEME_NODE_PRIVATE_H__
+#define __ST_THEME_NODE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#include "st-theme-node.h"
+
+G_BEGIN_DECLS
+
+struct _StThemeNode {
+ GObject parent;
+
+ StThemeContext *context;
+ StThemeNode *parent_node;
+ StTheme *theme;
+
+ PangoFontDescription *font_desc;
+
+ ClutterColor background_color;
+ /* If gradient is set, then background_color is the gradient start */
+ StGradientType background_gradient_type;
+ ClutterColor background_gradient_end;
+
+ ClutterColor foreground_color;
+ ClutterColor border_color[4];
+
+ int border_width[4];
+ int border_radius[4];
+ guint padding[4];
+
+ int width;
+ int height;
+ int min_width;
+ int min_height;
+ int max_width;
+ int max_height;
+
+ char *background_image;
+ StBorderImage *border_image;
+ StShadow *shadow;
+
+ GType element_type;
+ char *element_id;
+ char *element_class;
+ char *pseudo_class;
+ char *inline_style;
+
+ CRDeclaration **properties;
+ int n_properties;
+
+ /* We hold onto these separately so we can destroy them on finalize */
+ CRDeclaration *inline_properties;
+
+ guint properties_computed : 1;
+ guint geometry_computed : 1;
+ guint background_computed : 1;
+ guint foreground_computed : 1;
+ guint border_image_computed : 1;
+ guint shadow_computed : 1;
+ guint link_type : 2;
+
+ /* Graphics state */
+ float alloc_width;
+ float alloc_height;
+
+ CoglHandle shadow_material;
+ CoglHandle background_texture;
+ CoglHandle border_texture;
+ CoglHandle corner_texture;
+};
+
+struct _StThemeNodeClass {
+ GObjectClass parent_class;
+
+};
+
+void _st_theme_node_ensure_background (StThemeNode *node);
+void _st_theme_node_ensure_geometry (StThemeNode *node);
+
+void _st_theme_node_init_drawing_state (StThemeNode *node);
+void _st_theme_node_free_drawing_state (StThemeNode *node);
+
+G_END_DECLS
+
+#endif /* __ST_THEME_NODE_PRIVATE_H__ */
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index 5492a94..1b8b4d0 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -5,70 +5,12 @@
#include "st-theme-private.h"
#include "st-theme-context.h"
-#include "st-theme-node.h"
+#include "st-theme-node-private.h"
static void st_theme_node_init (StThemeNode *node);
static void st_theme_node_class_init (StThemeNodeClass *klass);
static void st_theme_node_finalize (GObject *object);
-struct _StThemeNode {
- GObject parent;
-
- StThemeContext *context;
- StThemeNode *parent_node;
- StTheme *theme;
-
- PangoFontDescription *font_desc;
-
- ClutterColor background_color;
- /* If gradient is set, then background_color is the gradient start */
- StGradientType background_gradient_type;
- ClutterColor background_gradient_end;
-
- ClutterColor foreground_color;
- ClutterColor border_color[4];
-
- int border_width[4];
- int border_radius[4];
- guint padding[4];
-
- int width;
- int height;
- int min_width;
- int min_height;
- int max_width;
- int max_height;
-
- char *background_image;
- StBorderImage *border_image;
- StShadow *shadow;
-
- GType element_type;
- char *element_id;
- char *element_class;
- char *pseudo_class;
- char *inline_style;
-
- CRDeclaration **properties;
- int n_properties;
-
- /* We hold onto these separately so we can destroy them on finalize */
- CRDeclaration *inline_properties;
-
- guint properties_computed : 1;
- guint geometry_computed : 1;
- guint background_computed : 1;
- guint foreground_computed : 1;
- guint border_image_computed : 1;
- guint shadow_computed : 1;
- guint link_type : 2;
-};
-
-struct _StThemeNodeClass {
- GObjectClass parent_class;
-
-};
-
static const ClutterColor BLACK_COLOR = { 0, 0, 0, 0xff };
static const ClutterColor TRANSPARENT_COLOR = { 0, 0, 0, 0 };
@@ -77,6 +19,7 @@ G_DEFINE_TYPE (StThemeNode, st_theme_node, G_TYPE_OBJECT)
static void
st_theme_node_init (StThemeNode *node)
{
+ _st_theme_node_init_drawing_state (node);
}
static void
@@ -131,6 +74,8 @@ st_theme_node_finalize (GObject *object)
if (node->background_image)
g_free (node->background_image);
+ _st_theme_node_free_drawing_state (node);
+
G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object);
}
@@ -259,7 +204,7 @@ st_theme_node_get_pseudo_class (StThemeNode *node)
return node->pseudo_class;
}
-static void
+void
ensure_properties (StThemeNode *node)
{
if (!node->properties_computed)
@@ -1108,8 +1053,8 @@ do_size_property (StThemeNode *node,
get_length_from_term_int (node, decl->value, FALSE, node_value);
}
-static void
-ensure_geometry (StThemeNode *node)
+void
+_st_theme_node_ensure_geometry (StThemeNode *node)
{
int i, j;
@@ -1192,7 +1137,7 @@ st_theme_node_get_border_width (StThemeNode *node,
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->border_width[side];
}
@@ -1204,7 +1149,7 @@ st_theme_node_get_border_radius (StThemeNode *node,
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
g_return_val_if_fail (corner >= ST_CORNER_TOPLEFT && corner <= ST_CORNER_BOTTOMLEFT, 0.);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->border_radius[corner];
}
@@ -1214,7 +1159,7 @@ st_theme_node_get_width (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->width;
}
@@ -1223,7 +1168,7 @@ st_theme_node_get_height (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->height;
}
@@ -1232,7 +1177,7 @@ st_theme_node_get_min_width (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->min_width;
}
@@ -1241,7 +1186,7 @@ st_theme_node_get_min_height (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->min_height;
}
@@ -1250,7 +1195,7 @@ st_theme_node_get_max_width (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->max_width;
}
@@ -1259,7 +1204,7 @@ st_theme_node_get_max_height (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->max_height;
}
@@ -1281,8 +1226,8 @@ get_background_color_from_term (StThemeNode *node,
return result;
}
-static void
-ensure_background (StThemeNode *node)
+void
+_st_theme_node_ensure_background (StThemeNode *node)
{
int i;
@@ -1429,7 +1374,7 @@ st_theme_node_get_background_color (StThemeNode *node,
{
g_return_if_fail (ST_IS_THEME_NODE (node));
- ensure_background (node);
+ _st_theme_node_ensure_background (node);
*color = node->background_color;
}
@@ -1439,7 +1384,7 @@ st_theme_node_get_background_image (StThemeNode *node)
{
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
- ensure_background (node);
+ _st_theme_node_ensure_background (node);
return node->background_image;
}
@@ -1500,7 +1445,7 @@ st_theme_node_get_background_gradient (StThemeNode *node,
{
g_return_if_fail (ST_IS_THEME_NODE (node));
- ensure_background (node);
+ _st_theme_node_ensure_background (node);
*type = node->background_gradient_type;
if (*type != ST_GRADIENT_NONE)
@@ -1518,7 +1463,7 @@ st_theme_node_get_border_color (StThemeNode *node,
g_return_if_fail (ST_IS_THEME_NODE (node));
g_return_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
*color = node->border_color[side];
}
@@ -1530,7 +1475,7 @@ st_theme_node_get_padding (StThemeNode *node,
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
return node->padding[side];
}
@@ -2353,7 +2298,7 @@ st_theme_node_adjust_preferred_width (StThemeNode *node,
g_return_if_fail (ST_IS_THEME_NODE (node));
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
width_inc = get_width_inc (node);
@@ -2420,7 +2365,7 @@ st_theme_node_adjust_preferred_height (StThemeNode *node,
g_return_if_fail (ST_IS_THEME_NODE (node));
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
height_inc = get_height_inc (node);
@@ -2461,7 +2406,7 @@ st_theme_node_get_content_box (StThemeNode *node,
g_return_if_fail (ST_IS_THEME_NODE (node));
- ensure_geometry (node);
+ _st_theme_node_ensure_geometry (node);
avail_width = allocation->x2 - allocation->x1;
avail_height = allocation->y2 - allocation->y1;
@@ -2501,8 +2446,8 @@ st_theme_node_geometry_equal (StThemeNode *node,
{
StSide side;
- ensure_geometry (node);
- ensure_geometry (other);
+ _st_theme_node_ensure_geometry (node);
+ _st_theme_node_ensure_geometry (other);
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
{
diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h
index 87c6884..2bc5e7a 100644
--- a/src/st/st-theme-node.h
+++ b/src/st/st-theme-node.h
@@ -171,6 +171,11 @@ void st_theme_node_get_content_box (StThemeNode *node,
gboolean st_theme_node_geometry_equal (StThemeNode *node,
StThemeNode *other);
+void st_theme_node_paint (StThemeNode *node,
+ const ClutterActorBox *box,
+ guint8 paint_opacity);
+
+
G_END_DECLS
#endif /* __ST_THEME_NODE_H__ */
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index 92e2d9a..dba5a04 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -38,9 +38,7 @@
#include "st-marshal.h"
#include "st-private.h"
-#include "st-shadow-texture.h"
#include "st-texture-cache.h"
-#include "st-texture-frame.h"
#include "st-theme-context.h"
#include "st-tooltip.h"
@@ -59,7 +57,6 @@ struct _StWidgetPrivate
ClutterActor *border_image;
ClutterActor *background_image;
- ClutterActor *background_image_shadow;
ClutterColor bg_color;
guint border_width;
@@ -68,6 +65,7 @@ struct _StWidgetPrivate
StGradientType bg_gradient_type;
ClutterColor bg_gradient_end;
+ ClutterActorBox background_allocation;
gdouble shadow_xoffset;
gdouble shadow_yoffset;
@@ -125,7 +123,6 @@ G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR);
static void st_widget_recompute_style (StWidget *widget,
StThemeNode *old_theme_node);
-static void st_widget_redraw_gradient (StWidget *widget);
static void
st_widget_set_property (GObject *gobject,
@@ -254,12 +251,6 @@ st_widget_dispose (GObject *gobject)
priv->border_image = NULL;
}
- if (priv->background_image_shadow)
- {
- clutter_actor_unparent (priv->background_image_shadow);
- priv->background_image_shadow = NULL;
- }
-
if (priv->theme_node)
{
g_object_unref (priv->theme_node);
@@ -295,18 +286,20 @@ st_widget_finalize (GObject *gobject)
G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject);
}
+
static void
st_widget_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
- StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
+ StWidget *self = ST_WIDGET (actor);
+ StWidgetPrivate *priv = self->priv;
StThemeNode *theme_node;
ClutterActorClass *klass;
ClutterGeometry area;
ClutterVertex in_v, out_v;
- theme_node = st_widget_get_theme_node ((StWidget*) actor);
+ theme_node = st_widget_get_theme_node (self);
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
klass->allocate (actor, box, flags);
@@ -327,249 +320,20 @@ st_widget_allocate (ClutterActor *actor,
st_tooltip_set_tip_area (priv->tooltip, &area);
}
-
-
-
- if (priv->border_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
- {
- ClutterActorBox frame_box;
-
- frame_box.x1 = frame_box.y1 = 0;
- frame_box.x2 = box->x2 - box->x1;
- frame_box.y2 = box->y2 - box->y1;
-
- clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
- &frame_box,
- flags);
- }
- else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
- {
- guint width, old_width,
- height, old_height;
- ClutterActorBox frame_box;
-
- frame_box.x1 = frame_box.y1 = 0;
- frame_box.x2 = box->x2 - box->x1;
- frame_box.y2 = box->y2 - box->y1;
-
- width = (guint)(0.5 + frame_box.x2);
- height = (guint)(0.5 + frame_box.y2);
-
- clutter_cairo_texture_get_surface_size (CLUTTER_CAIRO_TEXTURE (priv->border_image),
- &old_width, &old_height);
-
- if (width > 0 && height > 0 &&
- (old_width != width || old_height != height))
- {
-
- clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->border_image),
- width, height);
- st_widget_redraw_gradient ((StWidget*) actor);
- }
- clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
- &frame_box,
- flags);
- }
-
- if (priv->background_image)
- {
- ClutterActorBox frame_box;
- gfloat w, h;
-
- frame_box.x1 = frame_box.y1 = 0;
- frame_box.x2 = box->x2 - box->x1;
- frame_box.y2 = box->y2 - box->y1;
-
- clutter_actor_get_size (CLUTTER_ACTOR (priv->background_image), &w, &h);
-
- /* scale the background into the allocated bounds */
- if (w > frame_box.x2 || h > frame_box.y2)
- {
- gint new_h, new_w, offset;
- gint box_w, box_h;
-
- box_w = (int) frame_box.x2;
- box_h = (int) frame_box.y2;
-
- /* scale to fit */
- new_h = (int)((h / w) * ((gfloat) box_w));
- new_w = (int)((w / h) * ((gfloat) box_h));
-
- if (new_h > box_h)
- {
- /* center for new width */
- offset = ((box_w) - new_w) * 0.5;
- frame_box.x1 = offset;
- frame_box.x2 = offset + new_w;
-
- frame_box.y2 = box_h;
- }
- else
- {
- /* center for new height */
- offset = ((box_h) - new_h) * 0.5;
- frame_box.y1 = offset;
- frame_box.y2 = offset + new_h;
-
- frame_box.x2 = box_w;
- }
-
- }
- else
- {
- /* center the background on the widget */
- frame_box.x1 = (int)(((box->x2 - box->x1) / 2) - (w / 2));
- frame_box.y1 = (int)(((box->y2 - box->y1) / 2) - (h / 2));
- frame_box.x2 = frame_box.x1 + w;
- frame_box.y2 = frame_box.y1 + h;
- }
-
- if (priv->background_image_shadow)
- {
- StShadowTexture *shadow;
- ClutterActorBox shadow_box;
-
- shadow_box.x1 = frame_box.x1 + priv->shadow_xoffset;
- shadow_box.y1 = frame_box.y1 + priv->shadow_yoffset;
- shadow_box.x2 = frame_box.x2 + priv->shadow_xoffset;
- shadow_box.y2 = frame_box.y2 + priv->shadow_yoffset;
-
- /* The shadow texture is larger than the original image due
- to blurring, so we let it adjust its size.
- When the original image has been scaled, this will change
- the effective blur radius - we ignore this for now. */
- shadow = ST_SHADOW_TEXTURE (priv->background_image_shadow);
- st_shadow_texture_adjust_allocation (shadow, &shadow_box);
-
- clutter_actor_allocate (priv->background_image_shadow,
- &shadow_box, flags);
- }
-
-
- clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
- &frame_box,
- flags);
- }
}
static void
-st_widget_real_draw_background (StWidget *self)
+st_widget_paint (ClutterActor *actor)
{
- StWidgetPrivate *priv = self->priv;
- ClutterActor *actor = CLUTTER_ACTOR (self);
- ClutterActorBox allocation = { 0, };
- gfloat w, h;
- guint8 opacity;
-
- clutter_actor_get_allocation_box (actor, &allocation);
- w = allocation.x2 - allocation.x1;
- h = allocation.y2 - allocation.y1;
-
- opacity = clutter_actor_get_paint_opacity (actor);
-
- /* Default implementation just draws the background
- * colour and the image on top
- */
- if (priv->draw_bg_color)
- {
- ClutterColor bg_color = priv->bg_color;
-
- bg_color.alpha = opacity * bg_color.alpha / 255;
-
- cogl_set_source_color4ub (bg_color.red,
- bg_color.green,
- bg_color.blue,
- bg_color.alpha);
- cogl_rectangle (0, 0, w, h);
- }
-
- if (priv->draw_border_internal)
- {
- StThemeNode *node = st_widget_get_theme_node (self);
- int side;
- double border_top, border_right, border_bottom, border_left;
-
- border_top = st_theme_node_get_border_width (node, ST_SIDE_TOP);
- border_right = st_theme_node_get_border_width (node, ST_SIDE_RIGHT);
- border_bottom = st_theme_node_get_border_width (node, ST_SIDE_BOTTOM);
- border_left = st_theme_node_get_border_width (node, ST_SIDE_LEFT);
-
- for (side = 0; side < 4; side++)
- {
- ClutterColor color;
-
- switch (side)
- {
- case ST_SIDE_TOP:
- if (border_top <= 0)
- continue;
- break;
- case ST_SIDE_RIGHT:
- if (border_right <= 0)
- continue;
- break;
- case ST_SIDE_BOTTOM:
- if (border_bottom <= 0)
- continue;
- break;
- case ST_SIDE_LEFT:
- if (border_left <= 0)
- continue;
- break;
- }
-
- st_theme_node_get_border_color (node, side, &color);
-
- color.alpha = (color.alpha * opacity) / 0xff;
-
- cogl_set_source_color4ub (color.red,
- color.green,
- color.blue,
- color.alpha);
-
- /* Note top and bottom extend to the ends, left/right
- * are constrained by them. See comment above about CSS
- * conformance.
- */
- switch (side)
- {
- case ST_SIDE_TOP:
- cogl_rectangle (0, 0,
- w, border_top);
- break;
- case ST_SIDE_RIGHT:
- cogl_rectangle (w - border_right, border_top,
- w, h - border_bottom);
- break;
- case ST_SIDE_BOTTOM:
- cogl_rectangle (0, h - border_bottom,
- w, h);
- break;
- case ST_SIDE_LEFT:
- cogl_rectangle (0, border_top,
- border_left, h - border_bottom);
- break;
- }
- }
- }
-
- if (priv->border_image)
- clutter_actor_paint (priv->border_image);
-}
+ StWidget *self = ST_WIDGET (actor);
+ StThemeNode *theme_node;
+ ClutterActorBox allocation;
-static void
-st_widget_paint (ClutterActor *self)
-{
- StWidgetPrivate *priv = ST_WIDGET (self)->priv;
+ theme_node = st_widget_get_theme_node (self);
- st_widget_real_draw_background (ST_WIDGET (self));
+ clutter_actor_get_allocation_box (actor, &allocation);
- if (priv->background_image != NULL)
- {
- if (priv->background_image_shadow)
- clutter_actor_paint (priv->background_image_shadow);
- clutter_actor_paint (priv->background_image);
- }
+ st_theme_node_paint (theme_node, &allocation, clutter_actor_get_paint_opacity (actor));
}
static void
@@ -599,9 +363,6 @@ st_widget_map (ClutterActor *actor)
st_widget_ensure_style ((StWidget*) actor);
- if (priv->background_image_shadow)
- clutter_actor_map (priv->background_image_shadow);
-
if (priv->border_image)
clutter_actor_map (priv->border_image);
@@ -619,9 +380,6 @@ st_widget_unmap (ClutterActor *actor)
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->unmap (actor);
- if (priv->background_image_shadow)
- clutter_actor_unmap (priv->background_image_shadow);
-
if (priv->border_image)
clutter_actor_unmap (priv->border_image);
@@ -632,125 +390,6 @@ st_widget_unmap (ClutterActor *actor)
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
}
-static void
-st_widget_redraw_gradient (StWidget *widget)
-{
- ClutterCairoTexture *texture;
- ClutterColor *start, *end;
- StWidgetPrivate *priv;
- guint width, height;
- guint radius[4], i;
- cairo_t *cr;
- cairo_pattern_t *pattern;
- gboolean round_border = FALSE;
-
- if (widget->priv->bg_gradient_type == ST_GRADIENT_NONE)
- return;
-
- texture = CLUTTER_CAIRO_TEXTURE (widget->priv->border_image);
- priv = widget->priv;
- start = &widget->priv->bg_color;
- end = &widget->priv->bg_gradient_end;
-
- for (i = 0; i < 4; i++)
- {
- radius[i] = st_theme_node_get_border_radius (priv->theme_node, i);
- if (radius[i] > 0)
- round_border = TRUE;
- }
-
- clutter_cairo_texture_get_surface_size (texture, &width, &height);
- clutter_cairo_texture_clear (texture);
- cr = clutter_cairo_texture_create (texture);
-
- if (priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
- pattern = cairo_pattern_create_linear (0, 0, 0, height);
- else if (priv->bg_gradient_type == ST_GRADIENT_HORIZONTAL)
- pattern = cairo_pattern_create_linear (0, 0, width, 0);
- else
- {
- gdouble cx, cy;
-
- cx = width / 2.;
- cy = height / 2.;
- pattern = cairo_pattern_create_radial (cx, cy, 0, cx, cy, MIN (cx, cy));
- }
-
- cairo_pattern_add_color_stop_rgba (pattern, 0,
- start->red / 255.,
- start->green / 255.,
- start->blue / 255.,
- start->alpha / 255.);
- cairo_pattern_add_color_stop_rgba (pattern, 1,
- end->red / 255.,
- end->green / 255.,
- end->blue / 255.,
- end->alpha / 255.);
-
- if (round_border)
- {
- if (radius[ST_CORNER_TOPLEFT] > 0)
- cairo_arc (cr,
- radius[ST_CORNER_TOPLEFT],
- radius[ST_CORNER_TOPLEFT],
- radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
- else
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, width - radius[ST_CORNER_TOPRIGHT], 0);
- if (radius[ST_CORNER_TOPRIGHT] > 0)
- cairo_arc (cr,
- width - radius[ST_CORNER_TOPRIGHT],
- radius[ST_CORNER_TOPRIGHT],
- radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
- cairo_line_to (cr, width, height - radius[ST_CORNER_BOTTOMRIGHT]);
- if (radius[ST_CORNER_BOTTOMRIGHT])
- cairo_arc (cr,
- width - radius[ST_CORNER_BOTTOMRIGHT],
- height - radius[ST_CORNER_BOTTOMRIGHT],
- radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
- cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], height);
- if (radius[ST_CORNER_BOTTOMLEFT])
- cairo_arc (cr,
- radius[ST_CORNER_BOTTOMLEFT],
- height - radius[ST_CORNER_BOTTOMLEFT],
- radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
- cairo_close_path (cr);
- }
- else
- cairo_rectangle (cr, 0, 0, width, height);
-
- if (priv->border_width > 0)
- {
- guint8 opacity;
- gdouble effective_alpha;
- cairo_path_t *path;
-
- path = cairo_copy_path (cr);
- opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (widget));
- effective_alpha = priv->border_color.alpha * opacity / (255. * 255.);
-
- cairo_set_source_rgba (cr,
- priv->border_color.red / 255.,
- priv->border_color.green / 255.,
- priv->border_color.blue / 255.,
- effective_alpha);
- cairo_fill (cr);
-
- cairo_translate (cr, priv->border_width, priv->border_width);
- cairo_scale (cr,
- (gdouble)(width - 2 * priv->border_width) / width,
- (gdouble)(height - 2 * priv->border_width) / height);
- cairo_append_path (cr, path);
- cairo_path_destroy (path);
- }
-
- cairo_set_source (cr, pattern);
- cairo_fill (cr);
-
- cairo_pattern_destroy (pattern);
- cairo_destroy (cr);
-}
-
static void notify_children_of_style_change (ClutterContainer *container);
static void
@@ -776,270 +415,12 @@ static void
st_widget_real_style_changed (StWidget *self)
{
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
- StThemeNode *theme_node;
- StBorderImage *border_image;
- StShadow *shadow;
- StTextureCache *texture_cache;
- ClutterTexture *texture;
- const char *bg_file = NULL;
- gboolean relayout_needed = FALSE;
- gboolean has_changed = FALSE;
- ClutterColor color;
- guint border_radius = 0;
- StGradientType gradient;
- ClutterColor gradient_end;
- StSide side;
- StCorner corner;
- gboolean uniform_border_width;
/* application has request this widget is not stylable */
if (!priv->is_stylable)
return;
- theme_node = st_widget_get_theme_node (self);
-
- st_theme_node_get_background_gradient (theme_node, &gradient, &color, &gradient_end);
-
- if (gradient == ST_GRADIENT_NONE)
- {
- st_theme_node_get_background_color (theme_node, &color);
- if (gradient != priv->bg_gradient_type ||
- !clutter_color_equal (&color, &priv->bg_color))
- {
- priv->bg_gradient_type = gradient;
- priv->bg_color = color;
- priv->draw_bg_color = color.alpha != 0;
- has_changed = TRUE;
- }
- }
- else if (gradient != priv->bg_gradient_type ||
- !clutter_color_equal (&color, &priv->bg_color) ||
- !clutter_color_equal (&gradient_end, &priv->bg_gradient_end))
- {
- priv->bg_gradient_type = gradient;
- priv->bg_color = color;
- priv->bg_gradient_end = gradient_end;
- priv->draw_bg_color = TRUE;
- has_changed = TRUE;
- }
-
- if (priv->background_image_shadow)
- {
- clutter_actor_unparent (priv->background_image_shadow);
- priv->background_image_shadow = NULL;
- }
-
- if (priv->border_image)
- {
- clutter_actor_unparent (priv->border_image);
- priv->border_image = NULL;
- }
-
- if (priv->background_image)
- {
- clutter_actor_unparent (priv->background_image);
- priv->background_image = NULL;
- }
-
- texture_cache = st_texture_cache_get_default ();
-
-
- /* Rough notes about the relationship of borders and backgrounds in CSS3;
- * see http://www.w3.org/TR/css3-background/ for more accurate details.
- *
- * - Things are drawn in 4 layers, from the bottom:
- * Background color
- * Background image
- * Border color or border image
- * Content
- * - The background color, gradient and image extend to and are clipped by
- * the edge of the border area, so will be rounded if the border is
- * rounded. (CSS3 background-clip property modifies this)
- * - The border image replaces what would normally be drawn by the border
- * - The border image is not clipped by a rounded border-radius
- * - The border radius rounds the background even if the border is
- * zero width or a border image is being used.
- *
- * Deviations from the above as implemented here:
- * - Nonuniform border widths combined with a non-zero border radius result
- * in the border radius being ignored
- * - The combination of border image and a non-zero border radius is
- * not supported; the background color will be drawn with square
- * corners.
- * - The combination of border image and a background gradient is not
- * supported; the background will be drawn as a solid color
- * - The background image is drawn above the border color or image,
- * not below it.
- * - We don't clip the background image to the (rounded) border area.
- *
- * The first three allow us to always draw with no more than a single
- * border_image and a single background image above it.
- */
-
- /* Check whether all border widths are the same. Also, acquire the
- * first nonzero border width as well as the border color.
- */
- uniform_border_width = TRUE;
- priv->border_width = st_theme_node_get_border_width (theme_node,
- ST_SIDE_TOP);
- if (priv->border_width > 0.5)
- priv->border_width = (int)(0.5 + priv->border_width);
- for (side = 0; side < 4; side++)
- {
- double width = st_theme_node_get_border_width (theme_node, side);
- if (width > 0.5)
- width = (int)(0.5 + width);
- if (width > 0)
- {
- priv->border_width = width;
- st_theme_node_get_border_color (theme_node,
- side, &priv->border_color);
- }
- if ((int)width != priv->border_width)
- {
- uniform_border_width = FALSE;
- break;
- }
- }
-
- /* Pick the first nonzero border radius, but only if we have a uniform border. */
- if (uniform_border_width)
- {
- for (corner = 0; corner < 4; corner++)
- {
- double radius = st_theme_node_get_border_radius (theme_node, corner);
- if (radius > 0.5)
- {
- border_radius = (int)(0.5 + radius);
- break;
- }
- }
- }
-
- border_image = st_theme_node_get_border_image (theme_node);
- if (border_image)
- {
- const char *filename;
- gint border_left, border_right, border_top, border_bottom;
- gint width, height;
-
- filename = st_border_image_get_filename (border_image);
-
- /* `border-image' takes precedence over `background-image'.
- * Firefox lets the background-image shine thru when border-image has
- * alpha an channel, maybe that would be an option for the future. */
- texture = (ClutterTexture*) st_texture_cache_load_file_simple (texture_cache,
- filename);
-
- clutter_texture_get_base_size (CLUTTER_TEXTURE (texture),
- &width, &height);
-
- st_border_image_get_borders (border_image,
- &border_left, &border_right, &border_top, &border_bottom);
-
- priv->border_image = st_texture_frame_new (texture,
- border_top,
- border_right,
- border_bottom,
- border_left);
- clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
-
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
- else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
- {
- priv->draw_border_internal = FALSE;
- priv->draw_bg_color = FALSE;
- texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
- priv->border_image = CLUTTER_ACTOR (texture);
- clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
-
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
- else if (border_radius > 0)
- {
- priv->draw_border_internal = FALSE;
- priv->draw_bg_color = FALSE;
- priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
- "color", &priv->bg_color,
- "border-width", priv->border_width,
- "border-color", &priv->border_color,
- "corner-radius", border_radius,
- NULL);
-
- clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
-
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
- else if (priv->border_width > 0 && priv->border_color.alpha != 0)
- {
- priv->draw_bg_color = TRUE;
- priv->draw_border_internal = TRUE;
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
- else if (priv->draw_border_internal)
- {
- priv->draw_border_internal = FALSE;
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
-
- bg_file = st_theme_node_get_background_image (theme_node);
- if (bg_file != NULL)
- {
- priv->background_image = st_texture_cache_load_file_simple (texture_cache, bg_file);
- clutter_actor_set_parent (priv->background_image, CLUTTER_ACTOR (self));
-
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
-
- /* CSS based drop shadows
- *
- * Drop shadows in ST are modelled after the CSS3 box-shadow property;
- * see http://www.css3.info/preview/box-shadow/ for a detailed description.
- *
- * While the syntax of the property is mostly identical - we do not support
- * multiple shadows and allow for a more liberal placement of the color
- * parameter - its interpretation defers significantly in that the shadow's
- * shape is not determined by the bounding box, but by the CSS background
- * image (we could exend this in the future to take other CSS properties
- * like boder and background color into account).
- */
- shadow = st_theme_node_get_shadow (theme_node);
- if (shadow != NULL)
- {
- priv->shadow_xoffset = shadow->xoffset;
- priv->shadow_yoffset = shadow->yoffset;
-
- if (priv->background_image)
- {
- priv->background_image_shadow =
- st_shadow_texture_new (priv->background_image,
- &shadow->color,
- shadow->blur);
-
- clutter_actor_set_parent (priv->background_image_shadow,
- CLUTTER_ACTOR (self));
- has_changed = TRUE;
- relayout_needed = TRUE;
- }
- }
-
- /* If there are any properties above that need to cause a relayout they
- * should set this flag.
- */
- if (has_changed)
- {
- if (relayout_needed)
- clutter_actor_queue_relayout ((ClutterActor *) self);
- else
- clutter_actor_queue_redraw ((ClutterActor *) self);
- }
+ clutter_actor_queue_redraw ((ClutterActor *) self);
if (CLUTTER_IS_CONTAINER (self))
notify_children_of_style_change ((ClutterContainer *)self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]