forked from AuroraMiddleware/gtk
Merge branch 'wip/otte/conic' into 'master'
Add support for conic gradients See merge request GNOME/gtk!2911
This commit is contained in:
commit
35d2cbefe6
@ -83,6 +83,11 @@ gsk_radial_gradient_node_get_hradius
|
||||
gsk_radial_gradient_node_get_vradius
|
||||
gsk_radial_gradient_node_get_center
|
||||
gsk_repeating_radial_gradient_node_new
|
||||
gsk_conic_gradient_node_new
|
||||
gsk_conic_gradient_node_get_n_color_stops
|
||||
gsk_conic_gradient_node_get_color_stops
|
||||
gsk_conic_gradient_node_get_center
|
||||
gsk_conic_gradient_node_get_rotation
|
||||
gsk_border_node_new
|
||||
gsk_border_node_get_outline
|
||||
gsk_border_node_get_widths
|
||||
|
@ -4304,6 +4304,7 @@ gtk_snapshot_append_color
|
||||
gtk_snapshot_append_layout
|
||||
gtk_snapshot_append_linear_gradient
|
||||
gtk_snapshot_append_repeating_linear_gradient
|
||||
gtk_snapshot_append_conic_gradient
|
||||
gtk_snapshot_append_border
|
||||
gtk_snapshot_append_inset_shadow
|
||||
gtk_snapshot_append_outset_shadow
|
||||
|
@ -264,6 +264,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_REPEAT_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
@ -848,6 +849,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_REPEAT_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
|
@ -3723,6 +3723,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
default:
|
||||
{
|
||||
|
@ -32,6 +32,7 @@
|
||||
* @GSK_REPEATING_LINEAR_GRADIENT_NODE: A node drawing a repeating linear gradient
|
||||
* @GSK_RADIAL_GRADIENT_NODE: A node drawing a radial gradient
|
||||
* @GSK_REPEATING_RADIAL_GRADIENT_NODE: A node drawing a repeating radial gradient
|
||||
* @GSK_CONIC_GRADIENT_NODE: A node drawing a conic gradient
|
||||
* @GSK_BORDER_NODE: A node stroking a border around an area
|
||||
* @GSK_TEXTURE_NODE: A node drawing a #GdkTexture
|
||||
* @GSK_INSET_SHADOW_NODE: A node drawing an inset shadow
|
||||
@ -61,6 +62,7 @@ typedef enum {
|
||||
GSK_REPEATING_LINEAR_GRADIENT_NODE,
|
||||
GSK_RADIAL_GRADIENT_NODE,
|
||||
GSK_REPEATING_RADIAL_GRADIENT_NODE,
|
||||
GSK_CONIC_GRADIENT_NODE,
|
||||
GSK_BORDER_NODE,
|
||||
GSK_TEXTURE_NODE,
|
||||
GSK_INSET_SHADOW_NODE,
|
||||
|
@ -146,6 +146,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
|
||||
#define GSK_TYPE_REPEATING_LINEAR_GRADIENT_NODE (gsk_repeating_linear_gradient_node_get_type())
|
||||
#define GSK_TYPE_RADIAL_GRADIENT_NODE (gsk_radial_gradient_node_get_type())
|
||||
#define GSK_TYPE_REPEATING_RADIAL_GRADIENT_NODE (gsk_repeating_radial_gradient_node_get_type())
|
||||
#define GSK_TYPE_CONIC_GRADIENT_NODE (gsk_conic_gradient_node_get_type())
|
||||
#define GSK_TYPE_BORDER_NODE (gsk_border_node_get_type())
|
||||
#define GSK_TYPE_INSET_SHADOW_NODE (gsk_inset_shadow_node_get_type())
|
||||
#define GSK_TYPE_OUTSET_SHADOW_NODE (gsk_outset_shadow_node_get_type())
|
||||
@ -171,6 +172,7 @@ typedef struct _GskLinearGradientNode GskLinearGradientNode;
|
||||
typedef struct _GskRepeatingLinearGradientNode GskRepeatingLinearGradientNode;
|
||||
typedef struct _GskRadialGradientNode GskRadialGradientNode;
|
||||
typedef struct _GskRepeatingRadialGradientNode GskRepeatingRadialGradientNode;
|
||||
typedef struct _GskConicGradientNode GskConicGradientNode;
|
||||
typedef struct _GskBorderNode GskBorderNode;
|
||||
typedef struct _GskInsetShadowNode GskInsetShadowNode;
|
||||
typedef struct _GskOutsetShadowNode GskOutsetShadowNode;
|
||||
@ -242,6 +244,24 @@ GskRenderNode * gsk_repeating_linear_gradient_node_new (const graph
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_conic_gradient_node_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_conic_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *center,
|
||||
float rotation,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const graphene_point_t * gsk_conic_gradient_node_get_center (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
float gsk_conic_gradient_node_get_rotation (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gsize gsk_conic_gradient_node_get_n_color_stops (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const GskColorStop * gsk_conic_gradient_node_get_color_stops (GskRenderNode *node,
|
||||
gsize *n_stops);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_radial_gradient_node_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@ -768,6 +768,327 @@ gsk_radial_gradient_node_get_end (GskRenderNode *node)
|
||||
return self->end;
|
||||
}
|
||||
|
||||
/*** GSK_CONIC_GRADIENT_NODE ***/
|
||||
|
||||
struct _GskConicGradientNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
graphene_point_t center;
|
||||
float rotation;
|
||||
|
||||
gsize n_stops;
|
||||
GskColorStop *stops;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_CONIC_GRADIENT_NODE));
|
||||
|
||||
g_free (self->stops);
|
||||
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
#define DEG_TO_RAD(x) ((x) * (G_PI / 180.f))
|
||||
|
||||
static void
|
||||
_cairo_mesh_pattern_set_corner_rgba (cairo_pattern_t *pattern,
|
||||
guint corner_num,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, corner_num, rgba->red, rgba->green, rgba->blue, rgba->alpha);
|
||||
}
|
||||
|
||||
static void
|
||||
project (double angle,
|
||||
double radius,
|
||||
double *x_out,
|
||||
double *y_out)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
x = radius * cos (angle);
|
||||
y = radius * sin (angle);
|
||||
if (copysign (x, 1.0) > copysign (y, 1.0))
|
||||
{
|
||||
*x_out = copysign (radius, x);
|
||||
*y_out = y * radius / copysign (x, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x_out = x * radius / copysign (y, 1.0);
|
||||
*y_out = copysign (radius, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_add_patch (cairo_pattern_t *pattern,
|
||||
float radius,
|
||||
float start_angle,
|
||||
const GdkRGBA *start_color,
|
||||
float end_angle,
|
||||
const GdkRGBA *end_color)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
cairo_mesh_pattern_begin_patch (pattern);
|
||||
|
||||
cairo_mesh_pattern_move_to (pattern, 0, 0);
|
||||
project (start_angle, radius, &x, &y);
|
||||
cairo_mesh_pattern_line_to (pattern, x, y);
|
||||
project (end_angle, radius, &x, &y);
|
||||
cairo_mesh_pattern_line_to (pattern, x, y);
|
||||
cairo_mesh_pattern_line_to (pattern, 0, 0);
|
||||
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 0, start_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 1, start_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 2, end_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 3, end_color);
|
||||
|
||||
cairo_mesh_pattern_end_patch (pattern);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_rgba_color_interpolate (GdkRGBA *dest,
|
||||
const GdkRGBA *src1,
|
||||
const GdkRGBA *src2,
|
||||
double progress)
|
||||
{
|
||||
double alpha = src1->alpha * (1.0 - progress) + src2->alpha * progress;
|
||||
|
||||
dest->alpha = alpha;
|
||||
if (alpha == 0)
|
||||
{
|
||||
dest->red = src1->red * (1.0 - progress) + src2->red * progress;
|
||||
dest->green = src1->green * (1.0 - progress) + src2->green * progress;
|
||||
dest->blue = src1->blue * (1.0 - progress) + src2->blue * progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->red = (src1->red * src1->alpha * (1.0 - progress) + src2->red * src2->alpha * progress) / alpha;
|
||||
dest->green = (src1->green * src1->alpha * (1.0 - progress) + src2->green * src2->alpha * progress) / alpha;
|
||||
dest->blue = (src1->blue * src1->alpha * (1.0 - progress) + src2->blue * src2->alpha * progress) / alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
cairo_pattern_t *pattern;
|
||||
graphene_point_t corner;
|
||||
float radius;
|
||||
gsize i;
|
||||
|
||||
pattern = cairo_pattern_create_mesh ();
|
||||
graphene_rect_get_top_right (&node->bounds, &corner);
|
||||
radius = graphene_point_distance (&self->center, &corner, NULL, NULL);
|
||||
graphene_rect_get_bottom_right (&node->bounds, &corner);
|
||||
radius = MAX (radius, graphene_point_distance (&self->center, &corner, NULL, NULL));
|
||||
graphene_rect_get_bottom_left (&node->bounds, &corner);
|
||||
radius = MAX (radius, graphene_point_distance (&self->center, &corner, NULL, NULL));
|
||||
graphene_rect_get_top_left (&node->bounds, &corner);
|
||||
radius = MAX (radius, graphene_point_distance (&self->center, &corner, NULL, NULL));
|
||||
|
||||
for (i = 0; i <= self->n_stops; i++)
|
||||
{
|
||||
GskColorStop *stop1 = &self->stops[MAX (i, 1) - 1];
|
||||
GskColorStop *stop2 = &self->stops[MIN (i, self->n_stops - 1)];
|
||||
double offset1 = i > 0 ? stop1->offset : 0;
|
||||
double offset2 = i < self->n_stops ? stop2->offset : 1;
|
||||
double start_angle, end_angle;
|
||||
|
||||
offset1 = offset1 * 360 + self->rotation - 90;
|
||||
offset2 = offset2 * 360 + self->rotation - 90;
|
||||
|
||||
for (start_angle = offset1; start_angle < offset2; start_angle = end_angle)
|
||||
{
|
||||
GdkRGBA start_color, end_color;
|
||||
end_angle = (floor (start_angle / 45) + 1) * 45;
|
||||
end_angle = MIN (end_angle, offset2);
|
||||
gdk_rgba_color_interpolate (&start_color,
|
||||
&stop1->color,
|
||||
&stop2->color,
|
||||
(start_angle - offset1) / (offset2 - offset1));
|
||||
gdk_rgba_color_interpolate (&end_color,
|
||||
&stop1->color,
|
||||
&stop2->color,
|
||||
(end_angle - offset1) / (offset2 - offset1));
|
||||
|
||||
gsk_conic_gradient_node_add_patch (pattern,
|
||||
radius,
|
||||
DEG_TO_RAD (start_angle),
|
||||
&start_color,
|
||||
DEG_TO_RAD (end_angle),
|
||||
&end_color);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
||||
gsk_cairo_rectangle (cr, &node->bounds);
|
||||
cairo_translate (cr, self->center.x, self->center.y);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GskConicGradientNode *self1 = (GskConicGradientNode *) node1;
|
||||
GskConicGradientNode *self2 = (GskConicGradientNode *) node2;
|
||||
gsize i;
|
||||
|
||||
if (!graphene_point_equal (&self1->center, &self2->center) ||
|
||||
self1->rotation != self2->rotation ||
|
||||
self1->n_stops != self2->n_stops)
|
||||
{
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < self1->n_stops; i++)
|
||||
{
|
||||
GskColorStop *stop1 = &self1->stops[i];
|
||||
GskColorStop *stop2 = &self2->stops[i];
|
||||
|
||||
if (stop1->offset != stop2->offset ||
|
||||
!gdk_rgba_equal (&stop1->color, &stop2->color))
|
||||
{
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_conic_gradient_node_new:
|
||||
* @bounds: the bounds of the node
|
||||
* @center: the center of the gradient
|
||||
* @rotation: the rotation of the gradient in degrees
|
||||
* @color_stops: (array length=n_color_stops): a pointer to an array of #GskColorStop defining the gradient
|
||||
* The offsets of all color steps must be increasing. The first stop's offset must be >= 0 and the last
|
||||
* stop's offset must be <= 1.
|
||||
* @n_color_stops: the number of elements in @color_stops
|
||||
*
|
||||
* Creates a #GskRenderNode that draws a conic gradient. The conic gradient
|
||||
* starts around @center in the direction of @rotation. A rotation of 0 means
|
||||
* that the gradient points up. Color stops are then added clockwise.
|
||||
*
|
||||
* Returns: (transfer full) (type GskConicGradientNode): A new #GskRenderNode
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_conic_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *center,
|
||||
float rotation,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops)
|
||||
{
|
||||
GskConicGradientNode *self;
|
||||
GskRenderNode *node;
|
||||
gsize i;
|
||||
|
||||
g_return_val_if_fail (bounds != NULL, NULL);
|
||||
g_return_val_if_fail (center != NULL, NULL);
|
||||
g_return_val_if_fail (color_stops != NULL, NULL);
|
||||
g_return_val_if_fail (n_color_stops >= 2, NULL);
|
||||
g_return_val_if_fail (color_stops[0].offset >= 0, NULL);
|
||||
for (i = 1; i < n_color_stops; i++)
|
||||
g_return_val_if_fail (color_stops[i].offset >= color_stops[i - 1].offset, NULL);
|
||||
g_return_val_if_fail (color_stops[n_color_stops - 1].offset <= 1, NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_CONIC_GRADIENT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
graphene_point_init_from_point (&self->center, center);
|
||||
|
||||
self->rotation = rotation;
|
||||
|
||||
self->n_stops = n_color_stops;
|
||||
self->stops = g_malloc_n (n_color_stops, sizeof (GskColorStop));
|
||||
memcpy (self->stops, color_stops, n_color_stops * sizeof (GskColorStop));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_conic_gradient_node_get_n_color_stops:
|
||||
* @node: (type GskConicGradientNode): a #GskRenderNode for a conic gradient
|
||||
*
|
||||
* Retrieves the number of color stops in the gradient.
|
||||
*
|
||||
* Returns: the number of color stops
|
||||
*/
|
||||
gsize
|
||||
gsk_conic_gradient_node_get_n_color_stops (GskRenderNode *node)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
|
||||
return self->n_stops;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_conic_gradient_node_get_color_stops:
|
||||
* @node: (type GskConicGradientNode): a #GskRenderNode for a conic gradient
|
||||
* @n_stops: (out) (optional): the number of color stops in the returned array
|
||||
*
|
||||
* Retrieves the color stops in the gradient.
|
||||
*
|
||||
* Returns: (array length=n_stops): the color stops in the gradient
|
||||
*/
|
||||
const GskColorStop *
|
||||
gsk_conic_gradient_node_get_color_stops (GskRenderNode *node,
|
||||
gsize *n_stops)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
|
||||
if (n_stops != NULL)
|
||||
*n_stops = self->n_stops;
|
||||
|
||||
return self->stops;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_conic_gradient_node_get_center:
|
||||
* @node: (type GskConicGradientNode): a #GskRenderNode for a conic gradient
|
||||
*
|
||||
* Retrieves the center pointer for the gradient.
|
||||
*
|
||||
* Returns: the center point for the gradient
|
||||
*/
|
||||
const graphene_point_t *
|
||||
gsk_conic_gradient_node_get_center (GskRenderNode *node)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
|
||||
return &self->center;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_conic_gradient_node_get_rotation:
|
||||
* @node: (type GskConicGradientNode): a #GskRenderNode for a conic gradient
|
||||
*
|
||||
* Retrieves the rotation for the gradient in degrees.
|
||||
*
|
||||
* Returns: the rotation for the gradient
|
||||
*/
|
||||
float
|
||||
gsk_conic_gradient_node_get_rotation (GskRenderNode *node)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
|
||||
return self->rotation;
|
||||
}
|
||||
|
||||
/*** GSK_BORDER_NODE ***/
|
||||
|
||||
/**
|
||||
@ -4875,6 +5196,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_linear_gradient_node, GSK_LINEAR_GRADIENT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_linear_gradient_node, GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_radial_gradient_node, GSK_RADIAL_GRADIENT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_radial_gradient_node, GSK_REPEATING_RADIAL_GRADIENT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_conic_gradient_node, GSK_CONIC_GRADIENT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_border_node, GSK_BORDER_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_node, GSK_TEXTURE_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_inset_shadow_node, GSK_INSET_SHADOW_NODE)
|
||||
@ -5008,6 +5330,22 @@ gsk_render_node_init_types_once (void)
|
||||
gsk_render_node_types[GSK_REPEATING_RADIAL_GRADIENT_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
GSK_REPEATING_RADIAL_GRADIENT_NODE,
|
||||
sizeof (GskRadialGradientNode),
|
||||
NULL,
|
||||
gsk_conic_gradient_node_finalize,
|
||||
gsk_conic_gradient_node_draw,
|
||||
NULL,
|
||||
gsk_conic_gradient_node_diff,
|
||||
};
|
||||
|
||||
GType node_type = gsk_render_node_type_register_static (I_("GskConicGradientNode"), &node_info);
|
||||
gsk_render_node_types[GSK_CONIC_GRADIENT_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
|
@ -1070,6 +1070,40 @@ parse_repeating_radial_gradient_node (GtkCssParser *parser)
|
||||
return parse_radial_gradient_node_internal (parser, TRUE);
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_conic_gradient_node (GtkCssParser *parser)
|
||||
{
|
||||
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
|
||||
graphene_point_t center = GRAPHENE_POINT_INIT (25, 25);
|
||||
double rotation = 0.0;
|
||||
GArray *stops = NULL;
|
||||
const Declaration declarations[] = {
|
||||
{ "bounds", parse_rect, NULL, &bounds },
|
||||
{ "center", parse_point, NULL, ¢er },
|
||||
{ "rotation", parse_double, NULL, &rotation },
|
||||
{ "stops", parse_stops, clear_stops, &stops },
|
||||
};
|
||||
GskRenderNode *result;
|
||||
|
||||
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
|
||||
if (stops == NULL)
|
||||
{
|
||||
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
|
||||
GskColorStop to = { 1.0, GDK_RGBA("FF00CC") };
|
||||
|
||||
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop));
|
||||
g_array_append_val (stops, from);
|
||||
g_array_append_val (stops, to);
|
||||
}
|
||||
|
||||
result = gsk_conic_gradient_node_new (&bounds, ¢er, rotation,
|
||||
(GskColorStop *) stops->data, stops->len);
|
||||
|
||||
g_array_free (stops, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_inset_shadow_node (GtkCssParser *parser)
|
||||
{
|
||||
@ -1797,6 +1831,7 @@ parse_node (GtkCssParser *parser,
|
||||
{ "inset-shadow", parse_inset_shadow_node },
|
||||
{ "linear-gradient", parse_linear_gradient_node },
|
||||
{ "radial-gradient", parse_radial_gradient_node },
|
||||
{ "conic-gradient", parse_conic_gradient_node },
|
||||
{ "opacity", parse_opacity_node },
|
||||
{ "outset-shadow", parse_outset_shadow_node },
|
||||
{ "repeat", parse_repeat_node },
|
||||
@ -2184,6 +2219,30 @@ append_node_param (Printer *p,
|
||||
render_node_print (p, node);
|
||||
}
|
||||
|
||||
static void
|
||||
append_stops_param (Printer *p,
|
||||
const char *param_name,
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
_indent (p);
|
||||
g_string_append (p->str, param_name);
|
||||
g_string_append (p->str, ": ");
|
||||
|
||||
for (i = 0; i < n_stops; i ++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (p->str, ", ");
|
||||
|
||||
string_append_double (p->str, stops[i].offset);
|
||||
g_string_append_c (p->str, ' ');
|
||||
append_rgba (p->str, &stops[i].color);
|
||||
}
|
||||
g_string_append (p->str, ";\n");
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
cairo_write_array (void *closure,
|
||||
const unsigned char *data,
|
||||
@ -2294,10 +2353,6 @@ render_node_print (Printer *p,
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
{
|
||||
const gsize n_stops = gsk_linear_gradient_node_get_n_color_stops (node);
|
||||
const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL);
|
||||
gsize i;
|
||||
|
||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||
start_node (p, "repeating-linear-gradient");
|
||||
else
|
||||
@ -2306,19 +2361,8 @@ render_node_print (Printer *p,
|
||||
append_rect_param (p, "bounds", &node->bounds);
|
||||
append_point_param (p, "end", gsk_linear_gradient_node_get_end (node));
|
||||
append_point_param (p, "start", gsk_linear_gradient_node_get_start (node));
|
||||
|
||||
_indent (p);
|
||||
g_string_append (p->str, "stops: ");
|
||||
for (i = 0; i < n_stops; i ++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (p->str, ", ");
|
||||
|
||||
string_append_double (p->str, stops[i].offset);
|
||||
g_string_append_c (p->str, ' ');
|
||||
append_rgba (p->str, &stops[i].color);
|
||||
}
|
||||
g_string_append (p->str, ";\n");
|
||||
append_stops_param (p, "stops", gsk_linear_gradient_node_get_color_stops (node, NULL),
|
||||
gsk_linear_gradient_node_get_n_color_stops (node));
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
@ -2327,10 +2371,6 @@ render_node_print (Printer *p,
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
{
|
||||
const gsize n_stops = gsk_radial_gradient_node_get_n_color_stops (node);
|
||||
const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, NULL);
|
||||
gsize i;
|
||||
|
||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
|
||||
start_node (p, "repeating-radial-gradient");
|
||||
else
|
||||
@ -2343,18 +2383,23 @@ render_node_print (Printer *p,
|
||||
append_float_param (p, "start", gsk_radial_gradient_node_get_start (node), 0.0f);
|
||||
append_float_param (p, "end", gsk_radial_gradient_node_get_end (node), 1.0f);
|
||||
|
||||
_indent (p);
|
||||
g_string_append (p->str, "stops: ");
|
||||
for (i = 0; i < n_stops; i ++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (p->str, ", ");
|
||||
append_stops_param (p, "stops", gsk_radial_gradient_node_get_color_stops (node, NULL),
|
||||
gsk_radial_gradient_node_get_n_color_stops (node));
|
||||
|
||||
string_append_double (p->str, stops[i].offset);
|
||||
g_string_append_c (p->str, ' ');
|
||||
append_rgba (p->str, &stops[i].color);
|
||||
}
|
||||
g_string_append (p->str, ";\n");
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
{
|
||||
start_node (p, "conic-gradient");
|
||||
|
||||
append_rect_param (p, "bounds", &node->bounds);
|
||||
append_point_param (p, "center", gsk_conic_gradient_node_get_center (node));
|
||||
append_float_param (p, "rotation", gsk_conic_gradient_node_get_rotation (node), 0.0f);
|
||||
|
||||
append_stops_param (p, "stops", gsk_conic_gradient_node_get_color_stops (node, NULL),
|
||||
gsk_conic_gradient_node_get_n_color_stops (node));
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
|
@ -259,6 +259,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
||||
case GSK_SHADOW_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
default:
|
||||
FALLBACK ("Unsupported node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
|
||||
|
||||
|
@ -26,14 +26,15 @@
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/* for the types only */
|
||||
#include "gtk/gtkcssimageconicprivate.h"
|
||||
#include "gtk/gtkcssimagecrossfadeprivate.h"
|
||||
#include "gtk/gtkcssimagefallbackprivate.h"
|
||||
#include "gtk/gtkcssimageiconthemeprivate.h"
|
||||
#include "gtk/gtkcssimagelinearprivate.h"
|
||||
#include "gtk/gtkcssimageradialprivate.h"
|
||||
#include "gtk/gtkcssimageurlprivate.h"
|
||||
#include "gtk/gtkcssimagescaledprivate.h"
|
||||
#include "gtk/gtkcssimagerecolorprivate.h"
|
||||
#include "gtk/gtkcssimagefallbackprivate.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GtkCssImage, _gtk_css_image, G_TYPE_OBJECT)
|
||||
|
||||
@ -521,6 +522,7 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
|
||||
{ "repeating-linear-gradient", _gtk_css_image_linear_get_type },
|
||||
{ "radial-gradient", _gtk_css_image_radial_get_type },
|
||||
{ "repeating-radial-gradient", _gtk_css_image_radial_get_type },
|
||||
{ "conic-gradient", gtk_css_image_conic_get_type },
|
||||
{ "cross-fade", gtk_css_image_cross_fade_get_type },
|
||||
{ "image", _gtk_css_image_fallback_get_type }
|
||||
};
|
||||
|
529
gtk/gtkcssimageconic.c
Normal file
529
gtk/gtkcssimageconic.c
Normal file
@ -0,0 +1,529 @@
|
||||
/*
|
||||
* Copyright © 2012 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcssimageconicprivate.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtkcsspositionvalueprivate.h"
|
||||
#include "gtkcssprovider.h"
|
||||
|
||||
G_DEFINE_TYPE (GtkCssImageConic, gtk_css_image_conic, GTK_TYPE_CSS_IMAGE)
|
||||
|
||||
static void
|
||||
gtk_css_image_conic_snapshot (GtkCssImage *image,
|
||||
GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
|
||||
GskColorStop *stops;
|
||||
int i, last;
|
||||
double offset;
|
||||
|
||||
stops = g_newa (GskColorStop, self->n_stops);
|
||||
|
||||
last = -1;
|
||||
offset = 0;
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *stop = &self->color_stops[i];
|
||||
double pos, step;
|
||||
|
||||
if (stop->offset == NULL)
|
||||
{
|
||||
if (i == 0)
|
||||
pos = 0.0;
|
||||
else if (i + 1 == self->n_stops)
|
||||
pos = 1.0;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = _gtk_css_number_value_get (stop->offset, 360) / 360;
|
||||
pos = CLAMP (pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
pos = MAX (pos, offset);
|
||||
step = (pos - offset) / (i - last);
|
||||
for (last = last + 1; last <= i; last++)
|
||||
{
|
||||
stop = &self->color_stops[last];
|
||||
|
||||
offset += step;
|
||||
|
||||
stops[last].offset = offset;
|
||||
stops[last].color = *gtk_css_color_value_get_rgba (stop->color);
|
||||
}
|
||||
|
||||
offset = pos;
|
||||
last = i;
|
||||
}
|
||||
|
||||
gtk_snapshot_append_conic_gradient (
|
||||
snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (_gtk_css_position_value_get_x (self->center, width),
|
||||
_gtk_css_position_value_get_y (self->center, height)),
|
||||
_gtk_css_number_value_get (self->rotation, 360),
|
||||
stops,
|
||||
self->n_stops);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_angles (GtkCssParser *parser,
|
||||
gpointer option_data,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkCssValue **angles = option_data;
|
||||
|
||||
angles[0] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE | GTK_CSS_PARSE_PERCENT);
|
||||
if (angles[0] == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (gtk_css_number_value_can_parse (parser))
|
||||
{
|
||||
angles[1] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE | GTK_CSS_PARSE_PERCENT);
|
||||
if (angles[1] == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_color (GtkCssParser *parser,
|
||||
gpointer option_data,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkCssValue **color = option_data;
|
||||
|
||||
*color = _gtk_css_color_value_parse (parser);
|
||||
if (*color == NULL)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_css_image_conic_parse_color_stop (GtkCssImageConic *self,
|
||||
GtkCssParser *parser,
|
||||
GArray *stop_array)
|
||||
{
|
||||
GtkCssValue *angles[2] = { NULL, NULL };
|
||||
GtkCssValue *color = NULL;
|
||||
GtkCssParseOption options[] =
|
||||
{
|
||||
{ (void *) gtk_css_number_value_can_parse, parse_angles, &angles },
|
||||
{ (void *) gtk_css_color_value_can_parse, parse_color, &color },
|
||||
};
|
||||
|
||||
if (!gtk_css_parser_consume_any (parser, options, G_N_ELEMENTS (options), NULL))
|
||||
goto fail;
|
||||
|
||||
if (color == NULL)
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Expected shadow value to contain a length");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_array_append_vals (stop_array, (GtkCssImageConicColorStop[1]) {
|
||||
{ angles[0], color }
|
||||
},
|
||||
1);
|
||||
if (angles[1])
|
||||
g_array_append_vals (stop_array, (GtkCssImageConicColorStop[1]) {
|
||||
{ angles[1], gtk_css_value_ref (color) }
|
||||
},
|
||||
1);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
g_clear_pointer (&angles[0], gtk_css_value_unref);
|
||||
g_clear_pointer (&angles[1], gtk_css_value_unref);
|
||||
g_clear_pointer (&color, gtk_css_value_unref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_css_image_conic_parse_first_arg (GtkCssImageConic *self,
|
||||
GtkCssParser *parser,
|
||||
GArray *stop_array)
|
||||
{
|
||||
gboolean nothing_parsed = TRUE;
|
||||
|
||||
if (gtk_css_parser_try_ident (parser, "from"))
|
||||
{
|
||||
self->rotation = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
|
||||
if (self->rotation == NULL)
|
||||
return 0;
|
||||
nothing_parsed = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->rotation = _gtk_css_number_value_new (0, GTK_CSS_DEG);
|
||||
}
|
||||
|
||||
if (gtk_css_parser_try_ident (parser, "at"))
|
||||
{
|
||||
self->center = _gtk_css_position_value_parse (parser);
|
||||
if (self->center == NULL)
|
||||
return 0;
|
||||
nothing_parsed = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->center = _gtk_css_position_value_new (_gtk_css_number_value_new (50, GTK_CSS_PERCENT),
|
||||
_gtk_css_number_value_new (50, GTK_CSS_PERCENT));
|
||||
}
|
||||
|
||||
if (!nothing_parsed)
|
||||
return 1;
|
||||
|
||||
return 1 + gtk_css_image_conic_parse_color_stop (self, parser, stop_array);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkCssImageConic *self;
|
||||
GArray *stop_array;
|
||||
} ParseData;
|
||||
|
||||
static guint
|
||||
gtk_css_image_conic_parse_arg (GtkCssParser *parser,
|
||||
guint arg,
|
||||
gpointer user_data)
|
||||
{
|
||||
ParseData *parse_data = user_data;
|
||||
GtkCssImageConic *self = parse_data->self;
|
||||
|
||||
if (arg == 0)
|
||||
return gtk_css_image_conic_parse_first_arg (self, parser, parse_data->stop_array);
|
||||
else
|
||||
return gtk_css_image_conic_parse_color_stop (self, parser, parse_data->stop_array);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_conic_parse (GtkCssImage *image,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
|
||||
ParseData parse_data;
|
||||
gboolean success;
|
||||
|
||||
if (!gtk_css_parser_has_function (parser, "conic-gradient"))
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Not a conic gradient");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
parse_data.self = self;
|
||||
parse_data.stop_array = g_array_new (TRUE, FALSE, sizeof (GtkCssImageConicColorStop));
|
||||
|
||||
success = gtk_css_parser_consume_function (parser, 3, G_MAXUINT, gtk_css_image_conic_parse_arg, &parse_data);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
g_array_free (parse_data.stop_array, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->n_stops = parse_data.stop_array->len;
|
||||
self->color_stops = (GtkCssImageConicColorStop *)g_array_free (parse_data.stop_array, FALSE);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_conic_print (GtkCssImage *image,
|
||||
GString *string)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
|
||||
gboolean written = FALSE;
|
||||
guint i;
|
||||
|
||||
g_string_append (string, "self-gradient(");
|
||||
|
||||
if (self->center)
|
||||
{
|
||||
GtkCssValue *compare = _gtk_css_position_value_new (_gtk_css_number_value_new (50, GTK_CSS_PERCENT),
|
||||
_gtk_css_number_value_new (50, GTK_CSS_PERCENT));
|
||||
|
||||
if (!_gtk_css_value_equal (self->center, compare))
|
||||
{
|
||||
g_string_append (string, "from ");
|
||||
_gtk_css_value_print (self->center, string);
|
||||
written = TRUE;
|
||||
}
|
||||
|
||||
gtk_css_value_unref (compare);
|
||||
}
|
||||
|
||||
if (self->rotation && _gtk_css_number_value_get (self->rotation, 360) != 0)
|
||||
{
|
||||
if (written)
|
||||
g_string_append_c (string, ' ');
|
||||
g_string_append (string, "at ");
|
||||
_gtk_css_value_print (self->rotation, string);
|
||||
}
|
||||
|
||||
if (written)
|
||||
g_string_append (string, ", ");
|
||||
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *stop = &self->color_stops[i];
|
||||
|
||||
if (i > 0)
|
||||
g_string_append (string, ", ");
|
||||
|
||||
_gtk_css_value_print (stop->color, string);
|
||||
|
||||
if (stop->offset)
|
||||
{
|
||||
g_string_append (string, " ");
|
||||
_gtk_css_value_print (stop->offset, string);
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
gtk_css_image_conic_compute (GtkCssImage *image,
|
||||
guint property_id,
|
||||
GtkStyleProvider *provider,
|
||||
GtkCssStyle *style,
|
||||
GtkCssStyle *parent_style)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
|
||||
GtkCssImageConic *copy;
|
||||
guint i;
|
||||
|
||||
copy = g_object_new (GTK_TYPE_CSS_IMAGE_CONIC, NULL);
|
||||
|
||||
copy->center = _gtk_css_value_compute (self->center, property_id, provider, style, parent_style);
|
||||
copy->rotation = _gtk_css_value_compute (self->rotation, property_id, provider, style, parent_style);
|
||||
|
||||
copy->n_stops = self->n_stops;
|
||||
copy->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * copy->n_stops);
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *stop = &self->color_stops[i];
|
||||
GtkCssImageConicColorStop *scopy = ©->color_stops[i];
|
||||
|
||||
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style);
|
||||
|
||||
if (stop->offset)
|
||||
{
|
||||
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style);
|
||||
}
|
||||
else
|
||||
{
|
||||
scopy->offset = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return GTK_CSS_IMAGE (copy);
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
gtk_css_image_conic_transition (GtkCssImage *start_image,
|
||||
GtkCssImage *end_image,
|
||||
guint property_id,
|
||||
double progress)
|
||||
{
|
||||
GtkCssImageConic *start, *end, *result;
|
||||
guint i;
|
||||
|
||||
start = GTK_CSS_IMAGE_CONIC (start_image);
|
||||
|
||||
if (end_image == NULL)
|
||||
return GTK_CSS_IMAGE_CLASS (gtk_css_image_conic_parent_class)->transition (start_image, end_image, property_id, progress);
|
||||
|
||||
if (!GTK_IS_CSS_IMAGE_CONIC (end_image))
|
||||
return GTK_CSS_IMAGE_CLASS (gtk_css_image_conic_parent_class)->transition (start_image, end_image, property_id, progress);
|
||||
|
||||
end = GTK_CSS_IMAGE_CONIC (end_image);
|
||||
|
||||
if (start->n_stops != end->n_stops)
|
||||
return GTK_CSS_IMAGE_CLASS (gtk_css_image_conic_parent_class)->transition (start_image, end_image, property_id, progress);
|
||||
|
||||
result = g_object_new (GTK_TYPE_CSS_IMAGE_CONIC, NULL);
|
||||
|
||||
result->center = _gtk_css_value_transition (start->center, end->center, property_id, progress);
|
||||
if (result->center == NULL)
|
||||
goto fail;
|
||||
|
||||
result->rotation = _gtk_css_value_transition (start->rotation, end->rotation, property_id, progress);
|
||||
if (result->rotation == NULL)
|
||||
goto fail;
|
||||
|
||||
result->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * start->n_stops);
|
||||
result->n_stops = 0;
|
||||
for (i = 0; i < start->n_stops; i++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *start_stop = &start->color_stops[i];
|
||||
const GtkCssImageConicColorStop *end_stop = &end->color_stops[i];
|
||||
GtkCssImageConicColorStop *stop = &result->color_stops[i];
|
||||
|
||||
if ((start_stop->offset != NULL) != (end_stop->offset != NULL))
|
||||
goto fail;
|
||||
|
||||
if (start_stop->offset == NULL)
|
||||
{
|
||||
stop->offset = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stop->offset = _gtk_css_value_transition (start_stop->offset,
|
||||
end_stop->offset,
|
||||
property_id,
|
||||
progress);
|
||||
if (stop->offset == NULL)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
stop->color = _gtk_css_value_transition (start_stop->color,
|
||||
end_stop->color,
|
||||
property_id,
|
||||
progress);
|
||||
if (stop->color == NULL)
|
||||
{
|
||||
if (stop->offset)
|
||||
_gtk_css_value_unref (stop->offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result->n_stops ++;
|
||||
}
|
||||
|
||||
return GTK_CSS_IMAGE (result);
|
||||
|
||||
fail:
|
||||
g_object_unref (result);
|
||||
return GTK_CSS_IMAGE_CLASS (gtk_css_image_conic_parent_class)->transition (start_image, end_image, property_id, progress);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_conic_equal (GtkCssImage *image1,
|
||||
GtkCssImage *image2)
|
||||
{
|
||||
GtkCssImageConic *conic1 = (GtkCssImageConic *) image1;
|
||||
GtkCssImageConic *conic2 = (GtkCssImageConic *) image2;
|
||||
guint i;
|
||||
|
||||
if (!_gtk_css_value_equal (conic1->center, conic2->center) ||
|
||||
!_gtk_css_value_equal (conic1->rotation, conic2->rotation))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < conic1->n_stops; i++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *stop1 = &conic1->color_stops[i];
|
||||
const GtkCssImageConicColorStop *stop2 = &conic2->color_stops[i];
|
||||
|
||||
if (!_gtk_css_value_equal0 (stop1->offset, stop2->offset) ||
|
||||
!_gtk_css_value_equal (stop1->color, stop2->color))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_conic_dispose (GObject *object)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (object);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->n_stops; i ++)
|
||||
{
|
||||
GtkCssImageConicColorStop *stop = &self->color_stops[i];
|
||||
|
||||
_gtk_css_value_unref (stop->color);
|
||||
if (stop->offset)
|
||||
_gtk_css_value_unref (stop->offset);
|
||||
}
|
||||
g_free (self->color_stops);
|
||||
|
||||
g_clear_pointer (&self->center, gtk_css_value_unref);
|
||||
g_clear_pointer (&self->rotation, gtk_css_value_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_css_image_conic_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_conic_is_computed (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
|
||||
guint i;
|
||||
gboolean computed = TRUE;
|
||||
|
||||
computed = !self->center || gtk_css_value_is_computed (self->center);
|
||||
computed &= !self->rotation || gtk_css_value_is_computed (self->rotation);
|
||||
|
||||
for (i = 0; i < self->n_stops; i ++)
|
||||
{
|
||||
const GtkCssImageConicColorStop *stop = &self->color_stops[i];
|
||||
|
||||
if (stop->offset && !gtk_css_value_is_computed (stop->offset))
|
||||
{
|
||||
computed = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!gtk_css_value_is_computed (stop->color))
|
||||
{
|
||||
computed = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return computed;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_conic_class_init (GtkCssImageConicClass *klass)
|
||||
{
|
||||
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
image_class->snapshot = gtk_css_image_conic_snapshot;
|
||||
image_class->parse = gtk_css_image_conic_parse;
|
||||
image_class->print = gtk_css_image_conic_print;
|
||||
image_class->compute = gtk_css_image_conic_compute;
|
||||
image_class->equal = gtk_css_image_conic_equal;
|
||||
image_class->transition = gtk_css_image_conic_transition;
|
||||
image_class->is_computed = gtk_css_image_conic_is_computed;
|
||||
|
||||
object_class->dispose = gtk_css_image_conic_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_conic_init (GtkCssImageConic *self)
|
||||
{
|
||||
}
|
||||
|
64
gtk/gtkcssimageconicprivate.h
Normal file
64
gtk/gtkcssimageconicprivate.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright © 2012 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CSS_IMAGE_CONIC_PRIVATE_H__
|
||||
#define __GTK_CSS_IMAGE_CONIC_PRIVATE_H__
|
||||
|
||||
#include "gtk/gtkcssimageprivate.h"
|
||||
#include "gtk/gtkcssvalueprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_CSS_IMAGE_CONIC (gtk_css_image_conic_get_type ())
|
||||
#define GTK_CSS_IMAGE_CONIC(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_CONIC, GtkCssImageConic))
|
||||
#define GTK_CSS_IMAGE_CONIC_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_CONIC, GtkCssImageConicClass))
|
||||
#define GTK_IS_CSS_IMAGE_CONIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_CONIC))
|
||||
#define GTK_IS_CSS_IMAGE_CONIC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_CONIC))
|
||||
#define GTK_CSS_IMAGE_CONIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_CONIC, GtkCssImageConicClass))
|
||||
|
||||
typedef struct _GtkCssImageConic GtkCssImageConic;
|
||||
typedef struct _GtkCssImageConicClass GtkCssImageConicClass;
|
||||
typedef struct _GtkCssImageConicColorStop GtkCssImageConicColorStop;
|
||||
|
||||
struct _GtkCssImageConicColorStop {
|
||||
GtkCssValue *offset;
|
||||
GtkCssValue *color;
|
||||
};
|
||||
|
||||
struct _GtkCssImageConic
|
||||
{
|
||||
GtkCssImage parent;
|
||||
|
||||
GtkCssValue *center;
|
||||
GtkCssValue *rotation;
|
||||
|
||||
guint n_stops;
|
||||
GtkCssImageConicColorStop *color_stops;
|
||||
};
|
||||
|
||||
struct _GtkCssImageConicClass
|
||||
{
|
||||
GtkCssImageClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_css_image_conic_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CSS_IMAGE_CONIC_PRIVATE_H__ */
|
@ -2249,6 +2249,66 @@ gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot *snapshot,
|
||||
gtk_snapshot_append_node_internal (snapshot, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_append_conic_gradient:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
* @bounds: the rectangle to render the gradient into
|
||||
* @center: the center point of the conic gradient
|
||||
* @rotation: the clockwise rotation in degrees of the starting angle. 0 means the
|
||||
* starting angle is the top.
|
||||
* @stops: (array length=n_stops): a pointer to an array of #GskColorStop defining the gradient
|
||||
* @n_stops: the number of elements in @stops
|
||||
*
|
||||
* Appends a conic gradient node with the given stops to @snapshot.
|
||||
*/
|
||||
void
|
||||
gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
|
||||
const graphene_rect_t *bounds,
|
||||
const graphene_point_t *center,
|
||||
float rotation,
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
graphene_rect_t real_bounds;
|
||||
float dx, dy;
|
||||
const GdkRGBA *first_color;
|
||||
gboolean need_gradient = FALSE;
|
||||
int i;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
g_return_if_fail (center != NULL);
|
||||
g_return_if_fail (stops != NULL);
|
||||
g_return_if_fail (n_stops > 1);
|
||||
|
||||
gtk_snapshot_ensure_translate (snapshot, &dx, &dy);
|
||||
graphene_rect_offset_r (bounds, dx, dy, &real_bounds);
|
||||
|
||||
first_color = &stops[0].color;
|
||||
for (i = 0; i < n_stops; i ++)
|
||||
{
|
||||
if (!gdk_rgba_equal (first_color, &stops[i].color))
|
||||
{
|
||||
need_gradient = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_gradient)
|
||||
node = gsk_conic_gradient_node_new (&real_bounds,
|
||||
&GRAPHENE_POINT_INIT(
|
||||
center->x + dx,
|
||||
center->y + dy
|
||||
),
|
||||
rotation,
|
||||
stops,
|
||||
n_stops);
|
||||
else
|
||||
node = gsk_color_node_new (first_color, &real_bounds);
|
||||
|
||||
gtk_snapshot_append_node_internal (snapshot, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_append_radial_gradient:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
|
@ -191,6 +191,13 @@ void gtk_snapshot_append_repeating_radial_gradient (GtkSnapshot
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
|
||||
const graphene_rect_t *bounds,
|
||||
const graphene_point_t *center,
|
||||
float rotation,
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_append_border (GtkSnapshot *snapshot,
|
||||
const GskRoundedRect *outline,
|
||||
const float border_width[4],
|
||||
|
@ -133,6 +133,7 @@ create_list_model_for_render_node (GskRenderNode *node)
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_BORDER_NODE:
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
case GSK_OUTSET_SHADOW_NODE:
|
||||
@ -259,6 +260,8 @@ node_type_name (GskRenderNodeType type)
|
||||
return "Radial Gradient";
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
return "Repeating Radial Gradient";
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
return "Conic Gradient";
|
||||
case GSK_BORDER_NODE:
|
||||
return "Border";
|
||||
case GSK_TEXTURE_NODE:
|
||||
@ -308,6 +311,7 @@ node_name (GskRenderNode *node)
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_BORDER_NODE:
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
case GSK_OUTSET_SHADOW_NODE:
|
||||
@ -729,6 +733,44 @@ populate_render_node_properties (GtkListStore *store,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
{
|
||||
const graphene_point_t *center = gsk_conic_gradient_node_get_center (node);
|
||||
const float rotation = gsk_conic_gradient_node_get_rotation (node);
|
||||
const gsize n_stops = gsk_conic_gradient_node_get_n_color_stops (node);
|
||||
const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL);
|
||||
gsize i;
|
||||
GString *s;
|
||||
GdkTexture *texture;
|
||||
|
||||
tmp = g_strdup_printf ("%.2f, %.2f", center->x, center->y);
|
||||
add_text_row (store, "Center", tmp);
|
||||
g_free (tmp);
|
||||
|
||||
tmp = g_strdup_printf ("%.2f", rotation);
|
||||
add_text_row (store, "Rotation", tmp);
|
||||
g_free (tmp);
|
||||
|
||||
s = g_string_new ("");
|
||||
for (i = 0; i < n_stops; i++)
|
||||
{
|
||||
tmp = gdk_rgba_to_string (&stops[i].color);
|
||||
g_string_append_printf (s, "%.2f, %s\n", stops[i].offset, tmp);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
texture = get_linear_gradient_texture (n_stops, stops);
|
||||
gtk_list_store_insert_with_values (store, NULL, -1,
|
||||
0, "Color Stops",
|
||||
1, s->str,
|
||||
2, TRUE,
|
||||
3, texture,
|
||||
-1);
|
||||
g_string_free (s, TRUE);
|
||||
g_object_unref (texture);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_TEXT_NODE:
|
||||
{
|
||||
const PangoFont *font = gsk_text_node_get_font (node);
|
||||
|
@ -63,6 +63,7 @@ gtk_private_sources = files([
|
||||
'gtkcssfontfeaturesvalue.c',
|
||||
'gtkcssfontvariationsvalue.c',
|
||||
'gtkcssimage.c',
|
||||
'gtkcssimageconic.c',
|
||||
'gtkcssimagecrossfade.c',
|
||||
'gtkcssimagefallback.c',
|
||||
'gtkcssimageicontheme.c',
|
||||
|
Loading…
Reference in New Issue
Block a user