[gtk+] Add a render node for text
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Add a render node for text
- Date: Fri, 1 Sep 2017 17:30:41 +0000 (UTC)
commit 4975aa7920b0857a54114556c9830f7d9b69abfc
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Aug 29 17:28:10 2017 -0400
Add a render node for text
This is just a wrapper around a PangoGlyphString + PangoFont.
Basically, the arguments that are passed to pango_renderer_draw_glyphs.
gsk/gskenums.h | 4 +-
gsk/gskrendernode.h | 9 ++
gsk/gskrendernodeimpl.c | 245 +++++++++++++++++++++++++++++++-
gtk/inspector/gtktreemodelrendernode.c | 1 +
gtk/inspector/recorder.c | 2 +
5 files changed, 259 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index b2869e8..1141485 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -45,6 +45,7 @@
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
* @GSK_BLEND_NODE: A node that blends two children together
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
+ * @GSK_TEXT_NODE: A node containing a glyph string
*
* The type of a node determines what the node is rendering.
*
@@ -69,7 +70,8 @@ typedef enum {
GSK_ROUNDED_CLIP_NODE,
GSK_SHADOW_NODE,
GSK_BLEND_NODE,
- GSK_CROSS_FADE_NODE
+ GSK_CROSS_FADE_NODE,
+ GSK_TEXT_NODE
} GskRenderNodeType;
/**
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 0bbeed6..4c94f8d 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -174,6 +174,15 @@ GskRenderNode * gsk_cross_fade_node_new (GskRenderNode
GskRenderNode *end,
double progress);
+GDK_AVAILABLE_IN_3_92
+GskRenderNode * gsk_text_node_new (PangoFont *font,
+ PangoGlyphString *glyphs,
+ const GdkRGBA *color,
+ int x_offset,
+ int y_offset,
+ double base_x,
+ double base_y);
+
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_scaling_filters (GskRenderNode *node,
GskScalingFilter min_filter,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 214025b..2d04bb3 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -3801,6 +3801,248 @@ gsk_cross_fade_node_get_progress (GskRenderNode *node)
return self->progress;
}
+/*** GSK_TEXT_NODE ***/
+
+typedef struct _GskTextNode GskTextNode;
+
+struct _GskTextNode
+{
+ GskRenderNode render_node;
+
+ PangoFont *font;
+ PangoGlyphString *glyphs;
+ GdkRGBA color;
+ int x_offset;
+ int y_offset;
+ double base_x;
+ double base_y;
+};
+
+static void
+gsk_text_node_finalize (GskRenderNode *node)
+{
+ GskTextNode *self = (GskTextNode *) node;
+
+ g_object_unref (self->font);
+ pango_glyph_string_free (self->glyphs);
+}
+
+static gboolean
+_pango_cairo_font_install (PangoFont *font,
+ cairo_t *cr)
+{
+ cairo_scaled_font_t *scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
+
+ if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
+ return FALSE;
+
+ cairo_set_scaled_font (cr, scaled_font);
+
+ return TRUE;
+}
+
+#ifndef STACK_BUFFER_SIZE
+#define STACK_BUFFER_SIZE (512 * sizeof (int))
+#endif
+
+#define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T))
+
+static void
+gsk_text_node_draw (GskRenderNode *node,
+ cairo_t *cr)
+{
+ GskTextNode *self = (GskTextNode *) node;
+ int i, count;
+ int x_position = 0;
+ cairo_glyph_t *cairo_glyphs;
+ cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
+
+ cairo_save (cr);
+
+ cairo_translate (cr, self->x_offset, self->y_offset);
+
+ gdk_cairo_set_source_rgba (cr, &self->color);
+ if (!_pango_cairo_font_install (self->font, cr))
+ goto done;
+
+ if (self->glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
+ cairo_glyphs = g_new (cairo_glyph_t, self->glyphs->num_glyphs);
+ else
+ cairo_glyphs = stack_glyphs;
+
+ count = 0;
+ for (i = 0; i < self->glyphs->num_glyphs; i++)
+ {
+ PangoGlyphInfo *gi = &self->glyphs->glyphs[i];
+
+ if (gi->glyph != PANGO_GLYPH_EMPTY)
+ {
+ double cx = self->base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+ double cy = gi->geometry.y_offset == 0 ? self->base_y : self->base_y +
(double)(gi->geometry.y_offset) / PANGO_SCALE;
+
+ if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+ {
+ cairo_glyphs[count].index = gi->glyph;
+ cairo_glyphs[count].x = cx;
+ cairo_glyphs[count].y = cy;
+ count++;
+ }
+ }
+ x_position += gi->geometry.width;
+ }
+
+ cairo_show_glyphs (cr, cairo_glyphs, count);
+
+ if (cairo_glyphs != stack_glyphs)
+ g_free (cairo_glyphs);
+
+done:
+ cairo_restore (cr);
+}
+
+#define GSK_TEXT_NODE_VARIANT_TYPE "(sddddiidda(uiiii))"
+
+static GVariant *
+gsk_text_node_serialize (GskRenderNode *node)
+{
+ GskTextNode *self = (GskTextNode *) node;
+ GVariant *v;
+ GVariantBuilder builder;
+ int i;
+ PangoFontDescription *desc;
+ char *s;
+
+ desc = pango_font_describe (self->font);
+ s = pango_font_description_to_string (desc);
+ for (i = 0; i < self->glyphs->num_glyphs; i++)
+ {
+ PangoGlyphInfo *glyph = &self->glyphs->glyphs[i];
+ g_variant_builder_add (&builder, "(uiiii)",
+ glyph->glyph,
+ glyph->geometry.width,
+ glyph->geometry.x_offset,
+ glyph->geometry.y_offset,
+ glyph->attr.is_cluster_start);
+ }
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uiiii)"));
+ v = g_variant_new (GSK_TEXT_NODE_VARIANT_TYPE,
+ s,
+ self->color.red,
+ self->color.green,
+ self->color.blue,
+ self->color.alpha,
+ self->x_offset,
+ self->y_offset,
+ self->base_x,
+ self->base_y,
+ &builder);
+
+ g_free (s);
+ pango_font_description_free (desc);
+
+ return v;
+}
+
+static GskRenderNode *
+gsk_text_node_deserialize (GVariant *variant,
+ GError **error)
+{
+ PangoFont *font;
+ PangoGlyphString *glyphs;
+ GVariantIter iter;
+ GskRenderNode *result;
+ PangoGlyphInfo glyph;
+ PangoFontDescription *desc;
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ int cluster_start;
+ char *s;
+ GdkRGBA color;
+ int x_offset, y_offset;
+ double base_x, base_y;
+ int i;
+
+ if (!check_variant_type (variant, GSK_TEXT_NODE_VARIANT_TYPE, error))
+ return NULL;
+
+ g_variant_get (variant, "(&sddddiidda(uiiii))",
+ &color.red, &color.green, &color.blue, &color.alpha,
+ &x_offset, &y_offset,
+ &base_x, &base_y,
+ &s, &iter);
+
+ desc = pango_font_description_from_string (s);
+ fontmap = pango_cairo_font_map_get_default ();
+ context = pango_font_map_create_context (fontmap);
+ font = pango_font_map_load_font (fontmap, context, desc);
+
+ glyphs = pango_glyph_string_new ();
+ pango_glyph_string_set_size (glyphs, g_variant_iter_n_children (&iter));
+ i = 0;
+ while (g_variant_iter_next (&iter, "(uiiii)", &glyph.glyph, &glyph.geometry.width,
&glyph.geometry.x_offset, &glyph.geometry.y_offset, &cluster_start))
+ {
+ glyph.attr.is_cluster_start = cluster_start;
+ glyphs->glyphs[i] = glyph;
+ i++;
+ }
+
+ result = gsk_text_node_new (font, glyphs, &color, /* FIXME: Avoid copying glyphs */
+ x_offset, y_offset,
+ base_x, base_y);
+
+ pango_glyph_string_free (glyphs);
+ pango_font_description_free (desc);
+ g_object_unref (context);
+ g_object_unref (font);
+
+ return result;
+}
+
+static const GskRenderNodeClass GSK_TEXT_NODE_CLASS = {
+ GSK_TEXT_NODE,
+ sizeof (GskTextNode),
+ "GskTextNode",
+ gsk_text_node_finalize,
+ gsk_text_node_draw,
+ gsk_text_node_serialize,
+ gsk_text_node_deserialize
+};
+
+GskRenderNode *
+gsk_text_node_new (PangoFont *font,
+ PangoGlyphString *glyphs,
+ const GdkRGBA *color,
+ int x_offset,
+ int y_offset,
+ double base_x,
+ double base_y)
+{
+ GskTextNode *self;
+ PangoRectangle ink_rect;
+
+ self = (GskTextNode *) gsk_render_node_new (&GSK_TEXT_NODE_CLASS, 0);
+
+ self->font = g_object_ref (font);
+ self->glyphs = pango_glyph_string_copy (glyphs);
+ self->color = *color;
+ self->x_offset = x_offset;
+ self->y_offset = y_offset;
+ self->base_x = base_x;
+ self->base_y = base_y;
+
+ pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
+
+ graphene_rect_init (&self->render_node.bounds,
+ x_offset + base_x + ink_rect.x,
+ y_offset + base_y + ink_rect.y,
+ ink_rect.width,
+ ink_rect.height);
+
+ return &self->render_node;
+}
+
static const GskRenderNodeClass *klasses[] = {
[GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
[GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
@@ -3818,7 +4060,8 @@ static const GskRenderNodeClass *klasses[] = {
[GSK_ROUNDED_CLIP_NODE] = &GSK_ROUNDED_CLIP_NODE_CLASS,
[GSK_SHADOW_NODE] = &GSK_SHADOW_NODE_CLASS,
[GSK_BLEND_NODE] = &GSK_BLEND_NODE_CLASS,
- [GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS
+ [GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS,
+ [GSK_TEXT_NODE] = &GSK_TEXT_NODE_CLASS
};
GskRenderNode *
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index 63e3001..1697aaf 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -523,6 +523,7 @@ append_node (GtkTreeModelRenderNode *nodemodel,
break;
case GSK_CAIRO_NODE:
+ case GSK_TEXT_NODE:
case GSK_TEXTURE_NODE:
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 587c72e..e422b9e 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -181,6 +181,8 @@ node_type_name (GskRenderNodeType type)
return "Blend";
case GSK_CROSS_FADE_NODE:
return "CrossFade";
+ case GSK_TEXT_NODE:
+ return "Text";
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]