2017-11-17 11:04:02 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gskbroadwayrendererprivate.h"
|
|
|
|
#include "broadway/gdkprivate-broadway.h"
|
|
|
|
|
|
|
|
#include "gskdebugprivate.h"
|
2019-03-22 09:02:18 +00:00
|
|
|
#include "gsktransformprivate.h"
|
2017-11-17 11:04:02 +00:00
|
|
|
#include "gskrendererprivate.h"
|
|
|
|
#include "gskrendernodeprivate.h"
|
|
|
|
#include "gdk/gdktextureprivate.h"
|
|
|
|
|
|
|
|
struct _GskBroadwayRenderer
|
|
|
|
{
|
|
|
|
GskRenderer parent_instance;
|
2018-04-24 13:39:53 +00:00
|
|
|
GdkBroadwayDrawContext *draw_context;
|
2019-03-25 13:15:49 +00:00
|
|
|
guint32 next_node_id;
|
|
|
|
|
|
|
|
/* Set during rendering */
|
|
|
|
GArray *nodes; /* Owned by draw_contex */
|
|
|
|
GPtrArray *node_textures; /* Owned by draw_contex */
|
|
|
|
GHashTable *node_lookup;
|
|
|
|
|
|
|
|
/* Kept from last frame */
|
|
|
|
GHashTable *last_node_lookup;
|
|
|
|
GskRenderNode *last_root; /* Owning refs to the things in last_node_lookup */
|
2017-11-17 11:04:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _GskBroadwayRendererClass
|
|
|
|
{
|
|
|
|
GskRendererClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GskBroadwayRenderer, gsk_broadway_renderer, GSK_TYPE_RENDERER)
|
|
|
|
|
|
|
|
static gboolean
|
2018-04-24 13:39:53 +00:00
|
|
|
gsk_broadway_renderer_realize (GskRenderer *renderer,
|
|
|
|
GdkSurface *surface,
|
2017-11-17 11:04:02 +00:00
|
|
|
GError **error)
|
|
|
|
{
|
2018-04-24 13:39:53 +00:00
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
|
|
|
|
|
|
|
if (!GDK_IS_BROADWAY_SURFACE (surface))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
|
|
"Broadway renderer only works for broadway surfaces");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
self->draw_context = gdk_broadway_draw_context_context (surface);
|
|
|
|
|
2017-11-17 11:04:02 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-04-24 13:39:53 +00:00
|
|
|
gsk_broadway_renderer_unrealize (GskRenderer *renderer)
|
2017-11-17 11:04:02 +00:00
|
|
|
{
|
2018-04-24 13:39:53 +00:00
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
|
|
|
g_clear_object (&self->draw_context);
|
2017-11-17 11:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GdkTexture *
|
2018-04-24 13:39:53 +00:00
|
|
|
gsk_broadway_renderer_render_texture (GskRenderer *renderer,
|
2017-11-17 11:04:02 +00:00
|
|
|
GskRenderNode *root,
|
|
|
|
const graphene_rect_t *viewport)
|
|
|
|
{
|
|
|
|
GdkTexture *texture;
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height));
|
|
|
|
cr = cairo_create (surface);
|
|
|
|
|
|
|
|
cairo_translate (cr, - viewport->origin.x, - viewport->origin.y);
|
|
|
|
|
|
|
|
gsk_render_node_draw (root, cr);
|
|
|
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
texture = gdk_texture_new_for_surface (surface);
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2019-03-22 12:42:26 +00:00
|
|
|
/* uint32 is sent in native endianness, and then converted to little endian in broadwayd when sending to browser */
|
2017-11-17 11:04:02 +00:00
|
|
|
static void
|
2017-11-21 18:33:12 +00:00
|
|
|
add_uint32 (GArray *nodes, guint32 v)
|
2017-11-17 11:04:02 +00:00
|
|
|
{
|
2017-11-21 18:33:12 +00:00
|
|
|
g_array_append_val (nodes, v);
|
|
|
|
}
|
2017-11-17 11:04:02 +00:00
|
|
|
|
2019-03-22 12:42:26 +00:00
|
|
|
static void
|
|
|
|
add_float (GArray *nodes, float f)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
float f;
|
|
|
|
guint32 i;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
u.f = f;
|
|
|
|
g_array_append_val (nodes, u.i);
|
|
|
|
}
|
|
|
|
|
2017-11-21 20:56:06 +00:00
|
|
|
static guint32
|
|
|
|
rgba_to_uint32 (const GdkRGBA *rgba)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
((guint32)(0.5 + CLAMP (rgba->alpha, 0., 1.) * 255.) << 24) |
|
|
|
|
((guint32)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.) << 16) |
|
|
|
|
((guint32)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.) << 8) |
|
|
|
|
((guint32)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.) << 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_rgba (GArray *nodes, const GdkRGBA *rgba)
|
|
|
|
{
|
|
|
|
guint32 c = rgba_to_uint32 (rgba);
|
|
|
|
g_array_append_val (nodes, c);
|
|
|
|
}
|
|
|
|
|
2019-03-22 09:02:18 +00:00
|
|
|
static void
|
|
|
|
add_xy (GArray *nodes, float x, float y, float offset_x, float offset_y)
|
|
|
|
{
|
|
|
|
add_float (nodes, x - offset_x);
|
|
|
|
add_float (nodes, y - offset_y);
|
|
|
|
}
|
|
|
|
|
2017-11-21 22:01:00 +00:00
|
|
|
static void
|
2017-11-30 09:36:30 +00:00
|
|
|
add_point (GArray *nodes, const graphene_point_t *point, float offset_x, float offset_y)
|
2017-11-21 22:01:00 +00:00
|
|
|
{
|
2019-03-22 09:02:18 +00:00
|
|
|
add_xy (nodes, point->x, point->y, offset_x, offset_y);
|
2017-11-21 22:01:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_size (GArray *nodes, const graphene_size_t *size)
|
|
|
|
{
|
|
|
|
add_float (nodes, size->width);
|
|
|
|
add_float (nodes, size->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-11-30 09:36:30 +00:00
|
|
|
add_rect (GArray *nodes, const graphene_rect_t *rect, float offset_x, float offset_y)
|
2017-11-21 22:01:00 +00:00
|
|
|
{
|
2017-11-30 09:36:30 +00:00
|
|
|
add_point (nodes, &rect->origin, offset_x, offset_y);
|
2017-11-21 22:01:00 +00:00
|
|
|
add_size (nodes, &rect->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-11-30 09:36:30 +00:00
|
|
|
add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect, float offset_x, float offset_y)
|
2017-11-21 22:01:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2017-11-30 09:36:30 +00:00
|
|
|
add_rect (nodes, &rrect->bounds, offset_x, offset_y);
|
2017-11-21 22:01:00 +00:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
add_size (nodes, &rrect->corner[i]);
|
|
|
|
}
|
|
|
|
|
2019-03-27 18:27:16 +00:00
|
|
|
static void
|
|
|
|
add_matrix (GArray *nodes, graphene_matrix_t *matrix)
|
|
|
|
{
|
|
|
|
float matrix_floats[16];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
graphene_matrix_to_float (matrix, matrix_floats);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
add_float (nodes, matrix_floats[i]);
|
|
|
|
}
|
|
|
|
|
2017-11-22 11:31:36 +00:00
|
|
|
static void
|
|
|
|
add_color_stop (GArray *nodes, const GskColorStop *stop)
|
|
|
|
{
|
|
|
|
add_float (nodes, stop->offset);
|
|
|
|
add_rgba (nodes, &stop->color);
|
|
|
|
}
|
|
|
|
|
2019-03-22 11:42:12 +00:00
|
|
|
static void
|
|
|
|
add_string (GArray *nodes, const char *str)
|
|
|
|
{
|
|
|
|
guint32 len = strlen(str);
|
|
|
|
guint32 v, c;
|
|
|
|
|
|
|
|
add_uint32 (nodes, len);
|
|
|
|
|
|
|
|
v = 0;
|
|
|
|
c = 0;
|
|
|
|
while (*str != 0)
|
|
|
|
{
|
|
|
|
v |= (*str++) << 8*c++;
|
|
|
|
if (c == 4)
|
|
|
|
{
|
|
|
|
add_uint32 (nodes, v);
|
|
|
|
v = 0;
|
|
|
|
c = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != 0)
|
|
|
|
add_uint32 (nodes, v);
|
|
|
|
}
|
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
static void
|
|
|
|
collect_reused_child_nodes (GskRenderer *renderer,
|
|
|
|
GskRenderNode *node);
|
2017-11-22 14:39:09 +00:00
|
|
|
|
|
|
|
static void
|
2019-03-25 13:15:49 +00:00
|
|
|
collect_reused_node (GskRenderer *renderer,
|
|
|
|
GskRenderNode *node)
|
2017-11-22 14:39:09 +00:00
|
|
|
{
|
2019-03-25 13:15:49 +00:00
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
|
|
|
guint32 old_id;
|
|
|
|
|
|
|
|
if (self->last_node_lookup &&
|
|
|
|
(old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0)
|
|
|
|
{
|
|
|
|
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id));
|
|
|
|
collect_reused_child_nodes (renderer, node);
|
|
|
|
}
|
2017-11-22 14:39:09 +00:00
|
|
|
}
|
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
collect_reused_child_nodes (GskRenderer *renderer,
|
|
|
|
GskRenderNode *node)
|
2017-11-22 14:39:09 +00:00
|
|
|
{
|
2019-03-25 13:15:49 +00:00
|
|
|
guint i;
|
2017-11-22 14:39:09 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
switch (gsk_render_node_get_node_type (node))
|
|
|
|
{
|
|
|
|
case GSK_NOT_A_RENDER_NODE:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return;
|
2017-11-22 14:39:09 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
/* Leaf nodes */
|
2017-11-22 14:39:09 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
case GSK_TEXTURE_NODE:
|
|
|
|
case GSK_CAIRO_NODE:
|
|
|
|
case GSK_COLOR_NODE:
|
|
|
|
case GSK_BORDER_NODE:
|
|
|
|
case GSK_OUTSET_SHADOW_NODE:
|
|
|
|
case GSK_INSET_SHADOW_NODE:
|
|
|
|
case GSK_LINEAR_GRADIENT_NODE:
|
|
|
|
|
|
|
|
/* Fallbacks (=> leaf for now */
|
|
|
|
case GSK_COLOR_MATRIX_NODE:
|
|
|
|
case GSK_TEXT_NODE:
|
|
|
|
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
|
|
|
case GSK_REPEAT_NODE:
|
|
|
|
case GSK_BLEND_NODE:
|
|
|
|
case GSK_CROSS_FADE_NODE:
|
|
|
|
case GSK_BLUR_NODE:
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Bin nodes */
|
|
|
|
|
|
|
|
case GSK_SHADOW_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_shadow_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GSK_OPACITY_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_opacity_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GSK_ROUNDED_CLIP_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_rounded_clip_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GSK_CLIP_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_clip_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GSK_TRANSFORM_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_transform_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GSK_DEBUG_NODE:
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_debug_node_get_child (node));
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Generic nodes */
|
|
|
|
|
|
|
|
case GSK_CONTAINER_NODE:
|
|
|
|
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
|
|
|
|
collect_reused_node (renderer,
|
|
|
|
gsk_container_node_get_child (node, i));
|
|
|
|
break;
|
|
|
|
|
|
|
|
break; /* Fallback */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
add_new_node (GskRenderer *renderer,
|
|
|
|
GskRenderNode *node,
|
|
|
|
BroadwayNodeType type)
|
|
|
|
{
|
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
|
|
|
guint32 id, old_id;
|
|
|
|
|
|
|
|
if (self->last_node_lookup &&
|
|
|
|
(old_id = GPOINTER_TO_INT (g_hash_table_lookup (self->last_node_lookup, node))) != 0)
|
|
|
|
{
|
|
|
|
add_uint32 (self->nodes, BROADWAY_NODE_REUSE);
|
|
|
|
add_uint32 (self->nodes, old_id);
|
|
|
|
|
|
|
|
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(old_id));
|
|
|
|
collect_reused_child_nodes (renderer, node);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = ++self->next_node_id;
|
|
|
|
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id));
|
|
|
|
|
|
|
|
add_uint32 (self->nodes, type);
|
|
|
|
add_uint32 (self->nodes, id);
|
|
|
|
|
|
|
|
return TRUE;
|
2017-11-22 14:39:09 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 22:31:36 +00:00
|
|
|
typedef struct ColorizedTexture {
|
|
|
|
GdkTexture *texture;
|
|
|
|
graphene_matrix_t color_matrix;
|
|
|
|
graphene_vec4_t color_offset;
|
|
|
|
} ColorizedTexture;
|
|
|
|
|
|
|
|
static void
|
|
|
|
colorized_texture_free (ColorizedTexture *colorized)
|
|
|
|
{
|
|
|
|
g_object_unref (colorized->texture);
|
|
|
|
g_free (colorized);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColorizedTexture *
|
|
|
|
colorized_texture_new (GdkTexture *texture,
|
|
|
|
const graphene_matrix_t *color_matrix,
|
|
|
|
const graphene_vec4_t *color_offset)
|
|
|
|
{
|
|
|
|
ColorizedTexture *colorized = g_new0 (ColorizedTexture, 1);
|
|
|
|
colorized->texture = g_object_ref (texture);
|
|
|
|
colorized->color_matrix = *color_matrix;
|
|
|
|
colorized->color_offset = *color_offset;
|
|
|
|
return colorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
colorized_texture_free_list (GList *list)
|
|
|
|
{
|
|
|
|
g_list_free_full (list, (GDestroyNotify)colorized_texture_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
matrix_equal (const graphene_matrix_t *a,
|
|
|
|
const graphene_matrix_t *b)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; i ++)
|
|
|
|
{
|
|
|
|
graphene_vec4_t ra, rb;
|
|
|
|
graphene_matrix_get_row (a, i, &ra);
|
|
|
|
graphene_matrix_get_row (b, i, &rb);
|
|
|
|
if (!graphene_vec4_equal (&ra, &rb))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkTexture *
|
|
|
|
get_colorized_texture (GdkTexture *texture,
|
|
|
|
const graphene_matrix_t *color_matrix,
|
|
|
|
const graphene_vec4_t *color_offset)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surface = gdk_texture_download_surface (texture);
|
|
|
|
cairo_surface_t *image_surface;
|
|
|
|
graphene_vec4_t pixel;
|
|
|
|
guint32* pixel_data;
|
|
|
|
guchar *data;
|
|
|
|
gsize x, y, width, height, stride;
|
|
|
|
float alpha;
|
|
|
|
GdkTexture *colorized_texture;
|
|
|
|
GList *colorized_list, *l;
|
|
|
|
ColorizedTexture *colorized;
|
|
|
|
|
|
|
|
colorized_list = g_object_get_data (G_OBJECT (texture), "broadway-colorized");
|
|
|
|
|
|
|
|
for (l = colorized_list; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
colorized = l->data;
|
|
|
|
|
|
|
|
if (graphene_vec4_equal (&colorized->color_offset, color_offset) &&
|
|
|
|
matrix_equal (&colorized->color_matrix, color_matrix))
|
|
|
|
return g_object_ref (colorized->texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
image_surface = cairo_surface_map_to_image (surface, NULL);
|
|
|
|
data = cairo_image_surface_get_data (image_surface);
|
|
|
|
width = cairo_image_surface_get_width (image_surface);
|
|
|
|
height = cairo_image_surface_get_height (image_surface);
|
|
|
|
stride = cairo_image_surface_get_stride (image_surface);
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
pixel_data = (guint32 *) data;
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
|
|
|
|
|
|
|
|
if (alpha == 0)
|
|
|
|
{
|
|
|
|
graphene_vec4_init (&pixel, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
graphene_vec4_init (&pixel,
|
|
|
|
((pixel_data[x] >> 16) & 0xFF) / (255.0 * alpha),
|
|
|
|
((pixel_data[x] >> 8) & 0xFF) / (255.0 * alpha),
|
|
|
|
( pixel_data[x] & 0xFF) / (255.0 * alpha),
|
|
|
|
alpha);
|
|
|
|
graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel);
|
|
|
|
}
|
|
|
|
|
|
|
|
graphene_vec4_add (&pixel, color_offset, &pixel);
|
|
|
|
|
|
|
|
alpha = graphene_vec4_get_w (&pixel);
|
|
|
|
if (alpha > 0.0)
|
|
|
|
{
|
|
|
|
alpha = MIN (alpha, 1.0);
|
|
|
|
pixel_data[x] = (((guint32) (alpha * 255)) << 24) |
|
|
|
|
(((guint32) (CLAMP (graphene_vec4_get_x (&pixel), 0, 1) * alpha * 255)) << 16) |
|
|
|
|
(((guint32) (CLAMP (graphene_vec4_get_y (&pixel), 0, 1) * alpha * 255)) << 8) |
|
|
|
|
((guint32) (CLAMP (graphene_vec4_get_z (&pixel), 0, 1) * alpha * 255));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pixel_data[x] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data += stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_surface_mark_dirty (image_surface);
|
|
|
|
cairo_surface_unmap_image (surface, image_surface);
|
|
|
|
|
|
|
|
colorized_texture = gdk_texture_new_for_surface (surface);
|
|
|
|
|
|
|
|
colorized = colorized_texture_new (colorized_texture, color_matrix, color_offset);
|
|
|
|
if (colorized_list)
|
|
|
|
colorized_list = g_list_append (colorized_list, colorized);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
colorized_list = g_list_append (NULL, colorized);
|
|
|
|
g_object_set_data_full (G_OBJECT (texture), "broadway-colorized",
|
|
|
|
colorized_list, (GDestroyNotify)colorized_texture_free_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return colorized_texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-30 09:36:30 +00:00
|
|
|
/* Note: This tracks the offset so that we can convert
|
|
|
|
the absolute coordinates of the GskRenderNodes to
|
|
|
|
parent-relative which is what the dom uses, and
|
|
|
|
which is good for re-using subtrees. */
|
2017-11-21 18:33:12 +00:00
|
|
|
static void
|
2018-04-24 13:39:53 +00:00
|
|
|
gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
2017-11-30 09:36:30 +00:00
|
|
|
GskRenderNode *node,
|
|
|
|
float offset_x,
|
|
|
|
float offset_y)
|
2017-11-21 18:33:12 +00:00
|
|
|
{
|
2019-03-09 12:36:14 +00:00
|
|
|
GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer));
|
2019-03-22 14:29:24 +00:00
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
2019-03-25 13:15:49 +00:00
|
|
|
GArray *nodes = self->nodes;
|
2017-11-17 11:04:02 +00:00
|
|
|
|
2017-11-21 18:33:12 +00:00
|
|
|
switch (gsk_render_node_get_node_type (node))
|
2017-11-17 11:04:02 +00:00
|
|
|
{
|
2017-11-21 18:33:12 +00:00
|
|
|
case GSK_NOT_A_RENDER_NODE:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return;
|
2017-11-22 17:24:20 +00:00
|
|
|
|
2017-11-30 09:36:30 +00:00
|
|
|
/* Leaf nodes */
|
|
|
|
|
2017-11-22 17:24:20 +00:00
|
|
|
case GSK_TEXTURE_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
|
|
|
{
|
|
|
|
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
|
|
|
guint32 texture_id;
|
2017-11-22 17:24:20 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
/* No need to add to self->node_textures here, the node will keep it alive until end of frame. */
|
2017-11-22 17:24:20 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
texture_id = gdk_broadway_display_ensure_texture (display, texture);
|
|
|
|
|
|
|
|
add_rect (nodes, &node->bounds, offset_x, offset_y);
|
|
|
|
add_uint32 (nodes, texture_id);
|
|
|
|
}
|
2017-11-22 17:24:20 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-22 22:42:29 +00:00
|
|
|
case GSK_CAIRO_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
|
|
|
{
|
|
|
|
cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node);
|
|
|
|
cairo_surface_t *image_surface = NULL;
|
|
|
|
GdkTexture *texture;
|
|
|
|
guint32 texture_id;
|
|
|
|
|
|
|
|
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
|
|
|
|
image_surface = cairo_surface_reference (surface);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cairo_t *cr;
|
|
|
|
image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
|
ceilf (node->bounds.size.width),
|
|
|
|
ceilf (node->bounds.size.height));
|
|
|
|
cr = cairo_create (image_surface);
|
|
|
|
cairo_set_source_surface (cr, surface, 0, 0);
|
|
|
|
cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
texture = gdk_texture_new_for_surface (image_surface);
|
|
|
|
g_ptr_array_add (self->node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */
|
|
|
|
texture_id = gdk_broadway_display_ensure_texture (display, texture);
|
|
|
|
|
|
|
|
add_rect (nodes, &node->bounds, offset_x, offset_y);
|
|
|
|
add_uint32 (nodes, texture_id);
|
|
|
|
|
|
|
|
cairo_surface_destroy (image_surface);
|
|
|
|
}
|
2017-11-22 22:42:29 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-21 20:56:06 +00:00
|
|
|
case GSK_COLOR_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_COLOR))
|
|
|
|
{
|
|
|
|
add_rect (nodes, &node->bounds, offset_x, offset_y);
|
|
|
|
add_rgba (nodes, gsk_color_node_peek_color (node));
|
|
|
|
}
|
2017-11-21 20:56:06 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-21 22:01:00 +00:00
|
|
|
case GSK_BORDER_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_BORDER))
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
add_float (nodes, gsk_border_node_peek_widths (node)[i]);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]);
|
|
|
|
}
|
2017-11-22 08:47:47 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case GSK_OUTSET_SHADOW_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW))
|
|
|
|
{
|
|
|
|
add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y);
|
|
|
|
add_rgba (nodes, gsk_outset_shadow_node_peek_color (node));
|
|
|
|
add_float (nodes, gsk_outset_shadow_node_get_dx (node));
|
|
|
|
add_float (nodes, gsk_outset_shadow_node_get_dy (node));
|
|
|
|
add_float (nodes, gsk_outset_shadow_node_get_spread (node));
|
|
|
|
add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node));
|
|
|
|
}
|
2017-11-21 22:01:00 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-22 08:59:22 +00:00
|
|
|
case GSK_INSET_SHADOW_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW))
|
|
|
|
{
|
|
|
|
add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y);
|
|
|
|
add_rgba (nodes, gsk_inset_shadow_node_peek_color (node));
|
|
|
|
add_float (nodes, gsk_inset_shadow_node_get_dx (node));
|
|
|
|
add_float (nodes, gsk_inset_shadow_node_get_dy (node));
|
|
|
|
add_float (nodes, gsk_inset_shadow_node_get_spread (node));
|
|
|
|
add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node));
|
|
|
|
}
|
2017-11-22 08:59:22 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-22 11:31:36 +00:00
|
|
|
case GSK_LINEAR_GRADIENT_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT))
|
|
|
|
{
|
|
|
|
guint i, n;
|
|
|
|
|
|
|
|
add_rect (nodes, &node->bounds, offset_x, offset_y);
|
|
|
|
add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y);
|
|
|
|
add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y);
|
|
|
|
n = gsk_linear_gradient_node_get_n_color_stops (node);
|
|
|
|
add_uint32 (nodes, n);
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]);
|
|
|
|
}
|
2017-11-22 11:31:36 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-30 09:36:30 +00:00
|
|
|
/* Bin nodes */
|
|
|
|
|
2017-11-22 15:53:15 +00:00
|
|
|
case GSK_SHADOW_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW))
|
|
|
|
{
|
|
|
|
gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node);
|
|
|
|
|
|
|
|
add_uint32 (nodes, n_shadows);
|
|
|
|
for (i = 0; i < n_shadows; i++)
|
|
|
|
{
|
|
|
|
const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
|
|
|
|
add_rgba (nodes, &shadow->color);
|
|
|
|
add_float (nodes, shadow->dx);
|
|
|
|
add_float (nodes, shadow->dy);
|
|
|
|
add_float (nodes, shadow->radius);
|
|
|
|
}
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_shadow_node_get_child (node),
|
|
|
|
offset_x, offset_y);
|
|
|
|
}
|
2017-11-21 18:33:12 +00:00
|
|
|
return;
|
2017-11-22 15:53:15 +00:00
|
|
|
|
2017-11-22 16:28:44 +00:00
|
|
|
case GSK_OPACITY_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY))
|
|
|
|
{
|
|
|
|
add_float (nodes, gsk_opacity_node_get_opacity (node));
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_opacity_node_get_child (node),
|
|
|
|
offset_x, offset_y);
|
|
|
|
}
|
2017-11-30 09:36:30 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case GSK_ROUNDED_CLIP_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP))
|
|
|
|
{
|
|
|
|
const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node);
|
|
|
|
|
|
|
|
add_rounded_rect (nodes, rclip, offset_x, offset_y);
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_rounded_clip_node_get_child (node),
|
|
|
|
rclip->bounds.origin.x,
|
|
|
|
rclip->bounds.origin.y);
|
|
|
|
}
|
2017-11-22 16:40:39 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case GSK_CLIP_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_CLIP))
|
|
|
|
{
|
|
|
|
const graphene_rect_t *clip = gsk_clip_node_peek_clip (node);
|
|
|
|
|
|
|
|
add_rect (nodes, clip, offset_x, offset_y);
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_clip_node_get_child (node),
|
|
|
|
clip->origin.x,
|
|
|
|
clip->origin.y);
|
|
|
|
}
|
2017-11-30 09:36:30 +00:00
|
|
|
return;
|
|
|
|
|
2019-03-22 09:02:18 +00:00
|
|
|
case GSK_TRANSFORM_NODE:
|
|
|
|
{
|
|
|
|
GskTransform *transform = gsk_transform_node_get_transform (node);
|
|
|
|
GskTransformCategory category = gsk_transform_get_category (transform);
|
|
|
|
|
2019-03-27 18:27:16 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM)) {
|
|
|
|
if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
|
|
|
|
{
|
2019-03-25 13:15:49 +00:00
|
|
|
float dx, dy;
|
|
|
|
gsk_transform_to_translate (transform, &dx, &dy);
|
|
|
|
|
2019-03-27 18:27:16 +00:00
|
|
|
add_uint32 (nodes, 0); // Translate
|
|
|
|
add_xy (nodes, dx, dy, 0, 0);
|
2019-03-25 13:15:49 +00:00
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_transform_node_get_child (node),
|
|
|
|
0, 0);
|
|
|
|
}
|
2019-03-27 18:27:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
graphene_matrix_t matrix;
|
|
|
|
|
|
|
|
gsk_transform_to_matrix (transform, &matrix);
|
|
|
|
add_uint32 (nodes, 1); // General transform
|
|
|
|
add_matrix (nodes, &matrix);
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_transform_node_get_child (node),
|
|
|
|
0, 0);
|
|
|
|
}
|
|
|
|
}
|
2019-03-22 09:02:18 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2019-03-22 11:42:12 +00:00
|
|
|
case GSK_DEBUG_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG))
|
|
|
|
{
|
|
|
|
const char *message = gsk_debug_node_get_message (node);
|
|
|
|
add_string (nodes, message);
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_debug_node_get_child (node), offset_x, offset_y);
|
|
|
|
}
|
2019-03-22 11:42:12 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-30 09:36:30 +00:00
|
|
|
/* Generic nodes */
|
|
|
|
|
|
|
|
case GSK_CONTAINER_NODE:
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER))
|
|
|
|
{
|
|
|
|
guint i;
|
2017-11-30 09:36:30 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
add_uint32 (nodes, gsk_container_node_get_n_children (node));
|
|
|
|
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
|
|
|
|
gsk_broadway_renderer_add_node (renderer,
|
|
|
|
gsk_container_node_get_child (node, i), offset_x, offset_y);
|
|
|
|
}
|
2017-11-22 16:28:44 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case GSK_COLOR_MATRIX_NODE:
|
2019-03-28 22:31:36 +00:00
|
|
|
{
|
|
|
|
GskRenderNode *child = gsk_color_matrix_node_get_child (node);
|
|
|
|
if (gsk_render_node_get_node_type (child) == GSK_TEXTURE_NODE)
|
|
|
|
{
|
|
|
|
const graphene_matrix_t *color_matrix = gsk_color_matrix_node_peek_color_matrix (node);
|
|
|
|
const graphene_vec4_t *color_offset = gsk_color_matrix_node_peek_color_offset (node);
|
|
|
|
GdkTexture *texture = gsk_texture_node_get_texture (child);
|
|
|
|
GdkTexture *colorized_texture = get_colorized_texture (texture, color_matrix, color_offset);
|
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
|
|
|
{
|
|
|
|
guint32 texture_id = gdk_broadway_display_ensure_texture (display, colorized_texture);
|
|
|
|
add_rect (nodes, &child->bounds, offset_x, offset_y);
|
|
|
|
add_uint32 (nodes, texture_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-03-29 08:26:13 +00:00
|
|
|
break; /* Fallback */
|
2019-03-28 22:31:36 +00:00
|
|
|
|
2017-11-22 15:53:15 +00:00
|
|
|
case GSK_TEXT_NODE:
|
2017-11-24 13:51:22 +00:00
|
|
|
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
|
|
|
case GSK_REPEAT_NODE:
|
|
|
|
case GSK_BLEND_NODE:
|
|
|
|
case GSK_CROSS_FADE_NODE:
|
|
|
|
case GSK_BLUR_NODE:
|
2017-11-22 15:53:15 +00:00
|
|
|
default:
|
|
|
|
break; /* Fallback */
|
2017-11-17 11:04:02 +00:00
|
|
|
}
|
2017-11-22 15:53:15 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
|
|
|
|
{
|
|
|
|
GdkTexture *texture;
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
cairo_t *cr;
|
|
|
|
guint32 texture_id;
|
|
|
|
int x = floorf (node->bounds.origin.x);
|
|
|
|
int y = floorf (node->bounds.origin.y);
|
|
|
|
int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x;
|
|
|
|
int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y;
|
|
|
|
|
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
|
|
|
cr = cairo_create (surface);
|
|
|
|
cairo_translate (cr, -x, -y);
|
|
|
|
gsk_render_node_draw (node, cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
texture = gdk_texture_new_for_surface (surface);
|
|
|
|
g_ptr_array_add (self->node_textures, texture); /* Transfers ownership to node_textures */
|
|
|
|
|
|
|
|
texture_id = gdk_broadway_display_ensure_texture (display, texture);
|
|
|
|
add_float (nodes, x - offset_x);
|
|
|
|
add_float (nodes, y - offset_y);
|
|
|
|
add_float (nodes, gdk_texture_get_width (texture));
|
|
|
|
add_float (nodes, gdk_texture_get_height (texture));
|
|
|
|
add_uint32 (nodes, texture_id);
|
|
|
|
}
|
2019-03-22 14:29:24 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 18:33:12 +00:00
|
|
|
static void
|
2018-04-24 13:39:53 +00:00
|
|
|
gsk_broadway_renderer_render (GskRenderer *renderer,
|
2018-03-28 13:01:34 +00:00
|
|
|
GskRenderNode *root,
|
|
|
|
const cairo_region_t *update_area)
|
|
|
|
{
|
2018-04-24 13:39:53 +00:00
|
|
|
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
|
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
self->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
|
2019-03-22 14:29:24 +00:00
|
|
|
|
2018-04-24 13:39:53 +00:00
|
|
|
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area);
|
2019-03-25 13:15:49 +00:00
|
|
|
|
|
|
|
/* These are owned by the draw context between begin and end, but
|
|
|
|
cache them here for easier access during the render */
|
|
|
|
self->nodes = self->draw_context->nodes;
|
|
|
|
self->node_textures = self->draw_context->node_textures;
|
|
|
|
|
|
|
|
gsk_broadway_renderer_add_node (renderer, root, 0, 0);
|
|
|
|
|
|
|
|
self->nodes = NULL;
|
|
|
|
self->node_textures = NULL;
|
|
|
|
|
2018-04-24 13:39:53 +00:00
|
|
|
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context));
|
2019-03-22 14:29:24 +00:00
|
|
|
|
2019-03-25 13:15:49 +00:00
|
|
|
if (self->last_node_lookup)
|
|
|
|
g_hash_table_unref (self->last_node_lookup);
|
|
|
|
self->last_node_lookup = self->node_lookup;
|
|
|
|
self->node_lookup = NULL;
|
|
|
|
|
|
|
|
if (self->last_root)
|
|
|
|
gsk_render_node_unref (self->last_root);
|
|
|
|
self->last_root = gsk_render_node_ref (root);
|
|
|
|
|
|
|
|
if (self->next_node_id > G_MAXUINT32 / 2)
|
|
|
|
{
|
|
|
|
/* We're "near" a wrap of the ids, lets avoid reusing any of
|
|
|
|
* these nodes next frame, then we can reset the id counter
|
|
|
|
* without risk of any old nodes sticking around and conflicting. */
|
|
|
|
|
|
|
|
g_hash_table_remove_all (self->last_node_lookup);
|
|
|
|
self->next_node_id = 0;
|
|
|
|
}
|
2017-11-17 11:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gsk_broadway_renderer_class_init (GskBroadwayRendererClass *klass)
|
|
|
|
{
|
|
|
|
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
|
|
|
|
|
|
|
|
renderer_class->realize = gsk_broadway_renderer_realize;
|
|
|
|
renderer_class->unrealize = gsk_broadway_renderer_unrealize;
|
|
|
|
renderer_class->render = gsk_broadway_renderer_render;
|
|
|
|
renderer_class->render_texture = gsk_broadway_renderer_render_texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gsk_broadway_renderer_init (GskBroadwayRenderer *self)
|
|
|
|
{
|
|
|
|
}
|