diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index e30a1e1341..da16c7185b 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -3766,6 +3766,7 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job, gsk_gl_render_job_visit_transform_node (job, node); break; + case GSK_GLYPH_NODE: case GSK_CAIRO_NODE: gsk_gl_render_job_visit_as_fallback (job, node); break; diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 0dfeb0a0ea..cf0d3c3731 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -50,7 +50,7 @@ * @GSK_BLUR_NODE: A node that applies a blur * @GSK_DEBUG_NODE: Debug information that does not affect the rendering * @GSK_GL_SHADER_NODE: A node that uses OpenGL fragment shaders to render - + * * The type of a node determines what the node is rendering. */ typedef enum { @@ -79,7 +79,8 @@ typedef enum { GSK_TEXT_NODE, GSK_BLUR_NODE, GSK_DEBUG_NODE, - GSK_GL_SHADER_NODE + GSK_GL_SHADER_NODE, + GSK_GLYPH_NODE, } GskRenderNodeType; /** diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 3fa1d057c2..4d08490f61 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -164,6 +164,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes #define GSK_TYPE_TEXT_NODE (gsk_text_node_get_type()) #define GSK_TYPE_BLUR_NODE (gsk_blur_node_get_type()) #define GSK_TYPE_GL_SHADER_NODE (gsk_gl_shader_node_get_type()) +#define GSK_TYPE_GLYPH_NODE (gsk_glyph_node_get_type()) typedef struct _GskDebugNode GskDebugNode; typedef struct _GskColorNode GskColorNode; @@ -190,6 +191,7 @@ typedef struct _GskCrossFadeNode GskCrossFadeNode; typedef struct _GskTextNode GskTextNode; typedef struct _GskBlurNode GskBlurNode; typedef struct _GskGLShaderNode GskGLShaderNode; +typedef struct _GskGlyphNode GskGlyphNode; GDK_AVAILABLE_IN_ALL GType gsk_debug_node_get_type (void) G_GNUC_CONST; @@ -506,6 +508,29 @@ const GdkRGBA * gsk_text_node_get_color (const GskRender GDK_AVAILABLE_IN_ALL const graphene_point_t *gsk_text_node_get_offset (const GskRenderNode *node) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_10 +GType gsk_glyph_node_get_type (void) G_GNUC_CONST; +GDK_AVAILABLE_IN_4_10 +GskRenderNode * gsk_glyph_node_new (const graphene_rect_t *bounds, + hb_font_t *font, + hb_codepoint_t glyph, + unsigned int palette_index, + const GdkRGBA *foreground_color, + unsigned int n_colors, + const GdkRGBA *colors); +GDK_AVAILABLE_IN_4_10 +hb_font_t * gsk_glyph_node_get_font (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_10 +hb_codepoint_t gsk_glyph_node_get_glyph (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_10 +unsigned int gsk_glyph_node_get_palette_index (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_10 +const GdkRGBA * gsk_glyph_node_get_foreground_color (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_10 +unsigned int gsk_glyph_node_get_n_colors (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_10 +const GdkRGBA * gsk_glyph_node_get_colors (const GskRenderNode *node); + GDK_AVAILABLE_IN_ALL GType gsk_blur_node_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_ALL diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 8eaea1f20a..deabdcfed4 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -32,6 +32,7 @@ #include "gdk/gdkprivate.h" #include +#include /* maximal number of rectangles we keep in a diff region before we throw * the towel and just use the bounding box of the parent node. @@ -4660,6 +4661,208 @@ gsk_text_node_get_offset (const GskRenderNode *node) return &self->offset; } +/*** GSK_GLYPH_NODE ***/ + +struct _GskGlyphNode +{ + GskRenderNode render_node; + + hb_font_t *font; + hb_codepoint_t glyph; + unsigned int palette_index; + GdkRGBA foreground_color; + unsigned int n_colors; + GdkRGBA *colors; +}; + +static void +gsk_glyph_node_finalize (GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_GLYPH_NODE)); + + hb_font_destroy (self->font); + g_free (self->colors); + + parent_class->finalize (node); +} + +static void +gsk_glyph_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + unsigned int upem; + cairo_font_face_t *cairo_face; + cairo_matrix_t font_matrix, ctm; + cairo_font_options_t *font_options; + cairo_scaled_font_t *scaled_font; + hb_glyph_extents_t extents; + double scale; + cairo_glyph_t glyph; + + if (!hb_font_get_glyph_extents (self->font, self->glyph, &extents)) + return; + + if (extents.width <= 0 || extents.height == 0) + return; + + cairo_save (cr); + + upem = hb_face_get_upem (hb_font_get_face (self->font)); + + cairo_face = hb_cairo_font_face_create_for_font (self->font); + hb_cairo_font_face_set_scale_factor (cairo_face, 1 << 6); + + cairo_matrix_init_identity (&ctm); + cairo_matrix_init_scale (&font_matrix, (double)upem, (double)upem); + + font_options = cairo_font_options_create (); + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); +#ifdef CAIRO_COLOR_PALETTE_DEFAULT + cairo_font_options_set_color_palette (font_options, self->palette_index); +#endif +#ifdef HAVE_CAIRO_FONT_OPTIONS_SET_CUSTOM_PALETTE_COLOR + for (int i = 0; i < self->n_colors; i++) + cairo_font_options_set_custom_palette_color (font_options, i, + self->colors[i].red, + self->colors[i].green, + self->colors[i].blue, + self->colors[i].alpha); +#endif + + scaled_font = cairo_scaled_font_create (cairo_face, &font_matrix, &ctm, font_options); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (cairo_face); + + cairo_set_scaled_font (cr, scaled_font); + + cairo_scaled_font_destroy (scaled_font); + + scale = node->bounds.size.width * (1 << 6) / (double) extents.width; + + cairo_scale (cr, scale, scale); + + gdk_cairo_set_source_rgba (cr, &self->foreground_color); + + glyph.index = self->glyph; + glyph.x = - extents.x_bearing / (1 << 6); + glyph.y = extents.y_bearing / (1 << 6); + + cairo_show_glyphs (cr, &glyph, 1); + + cairo_restore (cr); +} + +static void +gsk_glyph_node_diff (GskRenderNode *node1, + GskRenderNode *node2, + cairo_region_t *region) +{ + GskGlyphNode *self1 = (GskGlyphNode *) node1; + GskGlyphNode *self2 = (GskGlyphNode *) node2; + + if (self1->font == self2->font && + self1->glyph == self2->glyph && + self1->palette_index == self2->palette_index && + gdk_rgba_equal (&self1->foreground_color, &self2->foreground_color) && + self1->n_colors == self2->n_colors) + { + for (unsigned int i = 0; i < self1->n_colors; i++) + { + if (!gdk_rgba_equal (&self1->colors[i], &self2->colors[i])) + { + gsk_render_node_diff_impossible (node1, node2, region); + return; + } + } + return; + } + + gsk_render_node_diff_impossible (node1, node2, region); +} + +GskRenderNode * +gsk_glyph_node_new (const graphene_rect_t *bounds, + hb_font_t *font, + hb_codepoint_t glyph, + unsigned int palette_index, + const GdkRGBA *foreground_color, + unsigned int n_colors, + const GdkRGBA *colors) +{ + GskGlyphNode *self; + GskRenderNode *node; + + self = gsk_render_node_alloc (GSK_GLYPH_NODE); + node = (GskRenderNode *) self; + node->offscreen_for_opacity = FALSE; + + self->font = hb_font_reference (font); + self->glyph = glyph; + self->palette_index = palette_index; + self->foreground_color = *foreground_color; + self->n_colors = n_colors; + + self->colors = g_new (GdkRGBA, n_colors); + for (unsigned int i = 0; i < n_colors; i++) + self->colors[i] = colors[i]; + + graphene_rect_init_from_rect (&node->bounds, bounds); + + return node; +} + +hb_font_t * +gsk_glyph_node_get_font (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return self->font; +} + +hb_codepoint_t +gsk_glyph_node_get_glyph (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return self->glyph; +} + +unsigned int +gsk_glyph_node_get_palette_index (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return self->palette_index; +} + +const GdkRGBA * +gsk_glyph_node_get_foreground_color (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return &self->foreground_color; +} + +unsigned int +gsk_glyph_node_get_n_colors (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return self->n_colors; +} + +const GdkRGBA * +gsk_glyph_node_get_colors (const GskRenderNode *node) +{ + GskGlyphNode *self = (GskGlyphNode *) node; + + return self->colors; +} + /*** GSK_BLUR_NODE ***/ /** @@ -5345,6 +5548,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_shadow_node, GSK_SHADOW_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE) +GSK_DEFINE_RENDER_NODE_TYPE (gsk_glyph_node, GSK_GLYPH_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE) @@ -5704,6 +5908,22 @@ gsk_render_node_init_types_once (void) gsk_render_node_types[GSK_TEXT_NODE] = node_type; } + { + const GskRenderNodeTypeInfo node_info = + { + GSK_GLYPH_NODE, + sizeof (GskGlyphNode), + NULL, + gsk_glyph_node_finalize, + gsk_glyph_node_draw, + NULL, + gsk_glyph_node_diff, + }; + + GType node_type = gsk_render_node_type_register_static (I_("GskGlyphNode"), &node_info); + gsk_render_node_types[GSK_GLYPH_NODE] = node_type; + } + { const GskRenderNodeTypeInfo node_info = { diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 68069b477e..e0518642ee 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -3043,6 +3043,8 @@ render_node_print (Printer *p, } break; + case GSK_GLYPH_NODE: + default: g_error ("Unhandled node: %s", g_type_name_from_instance ((GTypeInstance *) node)); break; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 02bd846979..cd70803bd8 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -13,7 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass; * We don't add an "n-types" value to avoid having to handle * it in every single switch. */ -#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_GL_SHADER_NODE + 1) +#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_GLYPH_NODE + 1) extern GType gsk_render_node_types[];