forked from AuroraMiddleware/gtk
gsk: Implement linear gradient render nodes
This commit is contained in:
parent
cf520b7a1f
commit
e8cd71228a
@ -33,6 +33,8 @@ GskScalingFilter
|
||||
gsk_render_node_set_scaling_filters
|
||||
gsk_render_node_set_name
|
||||
gsk_color_node_new
|
||||
gsk_linear_gradient_node_new
|
||||
gsk_repeating_linear_gradient_node_new
|
||||
gsk_texture_node_new
|
||||
gsk_cairo_node_new
|
||||
gsk_cairo_node_get_draw_context
|
||||
|
@ -28,6 +28,9 @@
|
||||
* @GSK_CONTAINER_NODE: A node containing a stack of children
|
||||
* @GSK_CAIRO_NODE: A node drawing a #cairo_surface_t
|
||||
* @GSK_COLOR_NODE: A node drawing a single color rectangle
|
||||
* @GSK_LINEAR_GRADIENT_NODE: A node drawing a linear gradient
|
||||
* @GSK_REPEATING_LINEAR_GRADIENT_NODE: A node drawing a repeating
|
||||
* linear gradient
|
||||
* @GSK_TEXTURE_NODE: A node drawing a #GskTexture
|
||||
* @GSK_TRANSFORM_NODE: A node that renders its child after applying a
|
||||
* matrix transform
|
||||
@ -45,6 +48,8 @@ typedef enum {
|
||||
GSK_CONTAINER_NODE,
|
||||
GSK_CAIRO_NODE,
|
||||
GSK_COLOR_NODE,
|
||||
GSK_LINEAR_GRADIENT_NODE,
|
||||
GSK_REPEATING_LINEAR_GRADIENT_NODE,
|
||||
GSK_TEXTURE_NODE,
|
||||
GSK_TRANSFORM_NODE,
|
||||
GSK_OPACITY_NODE,
|
||||
|
@ -33,6 +33,13 @@ G_BEGIN_DECLS
|
||||
#define GSK_IS_RENDER_NODE(obj) ((obj) != NULL)
|
||||
|
||||
typedef struct _GskRenderNode GskRenderNode;
|
||||
typedef struct _GskColorStop GskColorStop;
|
||||
|
||||
struct _GskColorStop
|
||||
{
|
||||
double offset;
|
||||
GdkRGBA color;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
GType gsk_render_node_get_type (void) G_GNUC_CONST;
|
||||
@ -53,6 +60,19 @@ GDK_AVAILABLE_IN_3_90
|
||||
GskRenderNode * gsk_texture_node_new (GskTexture *texture,
|
||||
const graphene_rect_t *bounds);
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
GskRenderNode * gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops);
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
GskRenderNode * gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops);
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
GskRenderNode * gsk_cairo_node_new (const graphene_rect_t *bounds);
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
|
@ -115,6 +115,162 @@ gsk_color_node_new (const GdkRGBA *rgba,
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
/*** GSK_LINEAR_GRADIENT_NODE ***/
|
||||
|
||||
typedef struct _GskLinearGradientNode GskLinearGradientNode;
|
||||
|
||||
struct _GskLinearGradientNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
graphene_rect_t bounds;
|
||||
|
||||
graphene_point_t start;
|
||||
graphene_point_t end;
|
||||
|
||||
GskColorStop *stops;
|
||||
gsize n_stops;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_linear_gradient_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskLinearGradientNode *self = (GskLinearGradientNode *) node;
|
||||
|
||||
g_free (self->stops);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_linear_gradient_node_make_immutable (GskRenderNode *node)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_linear_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskLinearGradientNode *self = (GskLinearGradientNode *) node;
|
||||
cairo_pattern_t *pattern;
|
||||
gsize i;
|
||||
|
||||
pattern = cairo_pattern_create_linear (self->start.x, self->start.y,
|
||||
self->end.x, self->end.y);
|
||||
|
||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgba (pattern,
|
||||
self->stops[i].offset,
|
||||
self->stops[i].color.red,
|
||||
self->stops[i].color.green,
|
||||
self->stops[i].color.blue,
|
||||
self->stops[i].color.alpha);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_rectangle (cr,
|
||||
self->bounds.origin.x, self->bounds.origin.y,
|
||||
self->bounds.size.width, self->bounds.size.height);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_linear_gradient_node_get_bounds (GskRenderNode *node,
|
||||
graphene_rect_t *bounds)
|
||||
{
|
||||
GskLinearGradientNode *self = (GskLinearGradientNode *) node;
|
||||
|
||||
graphene_rect_init_from_rect (bounds, &self->bounds);
|
||||
}
|
||||
|
||||
static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
|
||||
GSK_LINEAR_GRADIENT_NODE,
|
||||
sizeof (GskLinearGradientNode),
|
||||
"GskLinearGradientNode",
|
||||
gsk_linear_gradient_node_finalize,
|
||||
gsk_linear_gradient_node_make_immutable,
|
||||
gsk_linear_gradient_node_draw,
|
||||
gsk_linear_gradient_node_get_bounds
|
||||
};
|
||||
|
||||
static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
|
||||
GSK_REPEATING_LINEAR_GRADIENT_NODE,
|
||||
sizeof (GskLinearGradientNode),
|
||||
"GskLinearGradientNode",
|
||||
gsk_linear_gradient_node_finalize,
|
||||
gsk_linear_gradient_node_make_immutable,
|
||||
gsk_linear_gradient_node_draw,
|
||||
gsk_linear_gradient_node_get_bounds
|
||||
};
|
||||
|
||||
/**
|
||||
* gsk_linear_gradient_node_new:
|
||||
* @linear_gradient: the #GskLinearGradient
|
||||
* @bounds: the rectangle to render the linear_gradient into
|
||||
*
|
||||
* Creates a #GskRenderNode that will render the given
|
||||
* @linear_gradient into the area given by @bounds.
|
||||
*
|
||||
* Returns: A new #GskRenderNode
|
||||
*
|
||||
* Since: 3.90
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops)
|
||||
{
|
||||
GskLinearGradientNode *self;
|
||||
|
||||
g_return_val_if_fail (bounds != NULL, NULL);
|
||||
g_return_val_if_fail (start != NULL, NULL);
|
||||
g_return_val_if_fail (end != NULL, NULL);
|
||||
g_return_val_if_fail (color_stops != NULL, NULL);
|
||||
|
||||
self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_LINEAR_GRADIENT_NODE_CLASS);
|
||||
|
||||
graphene_rect_init_from_rect (&self->bounds, bounds);
|
||||
graphene_point_init_from_point (&self->start, start);
|
||||
graphene_point_init_from_point (&self->end, end);
|
||||
|
||||
self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
|
||||
self->n_stops = n_color_stops;
|
||||
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
|
||||
const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
const GskColorStop *color_stops,
|
||||
gsize n_color_stops)
|
||||
{
|
||||
GskLinearGradientNode *self;
|
||||
|
||||
g_return_val_if_fail (bounds != NULL, NULL);
|
||||
g_return_val_if_fail (start != NULL, NULL);
|
||||
g_return_val_if_fail (end != NULL, NULL);
|
||||
g_return_val_if_fail (color_stops != NULL, NULL);
|
||||
|
||||
self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS);
|
||||
|
||||
graphene_rect_init_from_rect (&self->bounds, bounds);
|
||||
graphene_point_init_from_point (&self->start, start);
|
||||
graphene_point_init_from_point (&self->end, end);
|
||||
|
||||
self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
|
||||
self->n_stops = n_color_stops;
|
||||
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
/*** GSK_TEXTURE_NODE ***/
|
||||
|
||||
typedef struct _GskTextureNode GskTextureNode;
|
||||
|
@ -128,19 +128,22 @@ gtk_css_image_linear_compute_start_point (double angle_in_degrees,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_linear_draw (GtkCssImage *image,
|
||||
cairo_t *cr,
|
||||
double width,
|
||||
double height)
|
||||
gtk_css_image_linear_snapshot (GtkCssImage *image,
|
||||
GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
|
||||
cairo_pattern_t *pattern;
|
||||
GskColorStop stops[linear->stops->len];
|
||||
GskRenderNode *node;
|
||||
double off_x, off_y; /* snapshot offset */
|
||||
double angle; /* actual angle of the gradiant line in degrees */
|
||||
double x, y; /* coordinates of start point */
|
||||
double length; /* distance in pixels for 100% */
|
||||
double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */
|
||||
double offset;
|
||||
int i, last;
|
||||
char *name;
|
||||
|
||||
if (linear->side)
|
||||
{
|
||||
@ -177,12 +180,6 @@ gtk_css_image_linear_draw (GtkCssImage *image,
|
||||
|
||||
length = sqrt (x * x + y * y);
|
||||
gtk_css_image_linear_get_start_end (linear, length, &start, &end);
|
||||
pattern = cairo_pattern_create_linear (x * (start - 0.5), y * (start - 0.5),
|
||||
x * (end - 0.5), y * (end - 0.5));
|
||||
if (linear->repeating)
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
else
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
||||
offset = start;
|
||||
last = -1;
|
||||
@ -209,31 +206,45 @@ gtk_css_image_linear_draw (GtkCssImage *image,
|
||||
step = (pos - offset) / (i - last);
|
||||
for (last = last + 1; last <= i; last++)
|
||||
{
|
||||
const GdkRGBA *rgba;
|
||||
|
||||
stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, last);
|
||||
|
||||
rgba = _gtk_css_rgba_value_get_rgba (stop->color);
|
||||
offset += step;
|
||||
|
||||
cairo_pattern_add_color_stop_rgba (pattern,
|
||||
(offset - start) / (end - start),
|
||||
rgba->red,
|
||||
rgba->green,
|
||||
rgba->blue,
|
||||
rgba->alpha);
|
||||
stops[last].offset = (offset - start) / (end - start);
|
||||
stops[last].color = *_gtk_css_rgba_value_get_rgba (stop->color);
|
||||
}
|
||||
|
||||
offset = pos;
|
||||
last = i;
|
||||
}
|
||||
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
cairo_translate (cr, width / 2, height / 2);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
gtk_snapshot_get_offset (snapshot, &off_x, &off_y);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
if (linear->repeating)
|
||||
{
|
||||
node = gsk_repeating_linear_gradient_node_new (
|
||||
&GRAPHENE_RECT_INIT (off_x, off_y, width, height),
|
||||
&GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
|
||||
&GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)),
|
||||
stops,
|
||||
linear->stops->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = gsk_linear_gradient_node_new (
|
||||
&GRAPHENE_RECT_INIT (off_x, off_y, width, height),
|
||||
&GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
|
||||
&GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)),
|
||||
stops,
|
||||
linear->stops->len);
|
||||
}
|
||||
name = g_strdup_printf ("%sLinearGradient<%ustops>", linear->repeating ? "Repeating" : "", linear->stops->len);
|
||||
gsk_render_node_set_name (node, name);
|
||||
g_free (name);
|
||||
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
||||
|
||||
@ -604,7 +615,7 @@ _gtk_css_image_linear_class_init (GtkCssImageLinearClass *klass)
|
||||
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
image_class->draw = gtk_css_image_linear_draw;
|
||||
image_class->snapshot = gtk_css_image_linear_snapshot;
|
||||
image_class->parse = gtk_css_image_linear_parse;
|
||||
image_class->print = gtk_css_image_linear_print;
|
||||
image_class->compute = gtk_css_image_linear_compute;
|
||||
|
@ -525,6 +525,8 @@ append_node (GtkTreeModelRenderNode *nodemodel,
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
/* no children */
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user