diff options
Diffstat (limited to 'gsk/gskvulkanrenderer.c')
-rw-r--r-- | gsk/gskvulkanrenderer.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c index 4ae0f4deee..7ae536f800 100644 --- a/gsk/gskvulkanrenderer.c +++ b/gsk/gskvulkanrenderer.c @@ -44,6 +44,8 @@ struct _GskVulkanRenderer GSList *textures; + GHashTable *glyph_cache; + #ifdef G_ENABLE_DEBUG ProfileTimers profile_timers; #endif @@ -343,3 +345,142 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self, return image; } + +#ifndef STACK_BUFFER_SIZE +#define STACK_BUFFER_SIZE (512 * sizeof (int)) +#endif + +#define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T)) + +static void +render_text (cairo_t *cr, + PangoFont *font, + PangoGlyphString *glyphs, + float x, + float y, + float width, + float height) +{ + int i, count; + int x_position = 0; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t *cairo_glyphs; + cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)]; + + scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font); + if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)) + return; + + cairo_set_scaled_font (cr, scaled_font); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + + if (glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs)) + cairo_glyphs = g_new (cairo_glyph_t, glyphs->num_glyphs); + else + cairo_glyphs = stack_glyphs; + + count = 0; + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *gi = &glyphs->glyphs[i]; + + if (gi->glyph != PANGO_GLYPH_EMPTY) + { + double cx = x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; + double cy = 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); +} + +GskVulkanImage * +gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self, + GskVulkanUploader *uploader, + PangoFont *font, + PangoGlyphString *glyphs) +{ + PangoRectangle ink_rect; + cairo_surface_t *surface; + cairo_t *cr; + GskVulkanImage *image; + + pango_glyph_string_extents (glyphs, font, &ink_rect, NULL); + pango_extents_to_pixels (&ink_rect, NULL); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ink_rect.x + ink_rect.width, + ink_rect.height); + + cr = cairo_create (surface); + render_text (cr, font, glyphs, 0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height); + cairo_destroy (cr); + + image = gsk_vulkan_image_new_from_data (uploader, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface), + cairo_image_surface_get_stride (surface)); + cairo_surface_destroy (surface); + + return image; +} + +static void +place_text (PangoFont *font, + PangoGlyphString *glyphs, + GskGlyphCoords *coords, + float x, + float y, + float width, + float height) +{ + int i; + int x_position = 0; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *gi = &glyphs->glyphs[i]; + + if (gi->glyph != PANGO_GLYPH_EMPTY) + { + double cx = x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; + + if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)) + { + coords[i].glyph = gi->glyph; + coords[i].x = cx / width; + coords[i].y = 0.0; + coords[i].width = (float)gi->geometry.width / (PANGO_SCALE * width); + coords[i].height = 1.0; // FIXME get actual glyph height + } + } + x_position += gi->geometry.width; + } +} + +void +gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self, + PangoFont *font, + PangoGlyphString *glyphs, + GskGlyphCoords *coords) +{ + PangoRectangle ink_rect; + + pango_glyph_string_extents (glyphs, font, &ink_rect, NULL); + pango_extents_to_pixels (&ink_rect, NULL); + + place_text (font, glyphs, coords, 0, - ink_rect.y, ink_rect.x + ink_rect.width, ink_rect.height); +} |