diff --git a/clutter/clutter/clutter-context.c b/clutter/clutter/clutter-context.c index 556234b4c..5dc8d3c31 100644 --- a/clutter/clutter/clutter-context.c +++ b/clutter/clutter/clutter-context.c @@ -31,7 +31,7 @@ #include "clutter/clutter-private.h" #include "clutter/clutter-paint-node-private.h" #include "clutter/clutter-settings-private.h" -#include "clutter/pango/cogl-pango-private.h" +#include "clutter/pango/clutter-pango-private.h" static gboolean clutter_show_fps = FALSE; static gboolean clutter_enable_accessibility = TRUE; @@ -321,7 +321,7 @@ clutter_context_get_pango_fontmap (ClutterContext *context) backend = clutter_context_get_backend (context); cogl_context = clutter_backend_get_cogl_context (backend); font_map = pango_cairo_font_map_new (); - font_renderer = _cogl_pango_renderer_new (cogl_context); + font_renderer = clutter_pango_renderer_new (cogl_context); resolution = clutter_backend_get_resolution (context->backend); pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), diff --git a/clutter/clutter/clutter-paint-nodes.c b/clutter/clutter/clutter-paint-nodes.c index 281b12ef5..6e4fe9920 100644 --- a/clutter/clutter/clutter-paint-nodes.c +++ b/clutter/clutter/clutter-paint-nodes.c @@ -30,7 +30,7 @@ #include #include "cogl/cogl.h" -#include "clutter/pango/cogl-pango-private.h" +#include "clutter/pango/clutter-pango-private.h" #include "clutter/clutter-actor-private.h" #include "clutter/clutter-blur-private.h" #include "clutter/clutter-debug.h" diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c index 0de768572..d35a25805 100644 --- a/clutter/clutter/clutter-text.c +++ b/clutter/clutter/clutter-text.c @@ -46,7 +46,7 @@ #include "clutter/clutter-text.h" -#include "clutter/pango/cogl-pango-private.h" +#include "clutter/pango/clutter-pango-private.h" #include "clutter/clutter-text-accessible-private.h" #include "clutter/clutter-actor-private.h" #include "clutter/clutter-animatable.h" diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build index 7ab1fa83e..d5f099477 100644 --- a/clutter/clutter/meson.build +++ b/clutter/clutter/meson.build @@ -84,10 +84,10 @@ clutter_headers = [ ] clutter_sources = [ - 'pango/cogl-pango-display-list.c', - 'pango/cogl-pango-glyph-cache.c', - 'pango/cogl-pango-pipeline-cache.c', - 'pango/cogl-pango-render.c', + 'pango/clutter-pango-display-list.c', + 'pango/clutter-pango-glyph-cache.c', + 'pango/clutter-pango-pipeline-cache.c', + 'pango/clutter-pango-render.c', 'clutter-accessibility.c', 'clutter-action.c', 'clutter-actor-box.c', @@ -181,10 +181,10 @@ clutter_sources = [ ] clutter_private_headers = [ - 'pango/cogl-pango-display-list.h', - 'pango/cogl-pango-glyph-cache.h', - 'pango/cogl-pango-pipeline-cache.h', - 'pango/cogl-pango-private.h', + 'pango/clutter-pango-display-list.h', + 'pango/clutter-pango-glyph-cache.h', + 'pango/clutter-pango-pipeline-cache.h', + 'pango/clutter-pango-private.h', 'clutter-accessibility-private.h', 'clutter-actor-meta-private.h', 'clutter-actor-private.h', diff --git a/clutter/clutter/pango/cogl-pango-display-list.c b/clutter/clutter/pango/clutter-pango-display-list.c similarity index 71% rename from clutter/clutter/pango/cogl-pango-display-list.c rename to clutter/clutter/pango/clutter-pango-display-list.c index 00521d47e..8a4125961 100644 --- a/clutter/clutter/pango/cogl-pango-display-list.c +++ b/clutter/clutter/pango/clutter-pango-display-list.c @@ -31,39 +31,36 @@ #include #include -#include "clutter/pango/cogl-pango-display-list.h" -#include "clutter/pango/cogl-pango-pipeline-cache.h" +#include "clutter/pango/clutter-pango-display-list.h" +#include "clutter/pango/clutter-pango-pipeline-cache.h" #include "cogl/cogl.h" typedef enum { - COGL_PANGO_DISPLAY_LIST_TEXTURE, - COGL_PANGO_DISPLAY_LIST_RECTANGLE, - COGL_PANGO_DISPLAY_LIST_TRAPEZOID -} CoglPangoDisplayListNodeType; + PANGO_DISPLAY_LIST_TEXTURE, + PANGO_DISPLAY_LIST_RECTANGLE, + PANGO_DISPLAY_LIST_TRAPEZOID +} PangoDisplayListNodeType; -typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; -typedef struct _CoglPangoDisplayListRectangle CoglPangoDisplayListRectangle; - -struct _CoglPangoDisplayList +struct _ClutterPangoDisplayList { - gboolean color_override; - CoglColor color; + gboolean color_override; + CoglColor color; GSList *nodes; GSList *last_node; - CoglPangoPipelineCache *pipeline_cache; + ClutterPangoPipelineCache *pipeline_cache; }; /* This matches the format expected by cogl_rectangles_with_texture_coords */ -struct _CoglPangoDisplayListRectangle +typedef struct _PangoDisplayListRectangle { float x_1, y_1, x_2, y_2; float s_1, t_1, s_2, t_2; -}; +} PangoDisplayListRectangle; -struct _CoglPangoDisplayListNode +typedef struct _PangoDisplayListNode { - CoglPangoDisplayListNodeType type; + PangoDisplayListNodeType type; gboolean color_override; CoglColor color; @@ -95,12 +92,12 @@ struct _CoglPangoDisplayListNode CoglPrimitive *primitive; } trapezoid; } d; -}; +} PangoDisplayListNode; -CoglPangoDisplayList * -_cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache) +ClutterPangoDisplayList * +clutter_pango_display_list_new (ClutterPangoPipelineCache *pipeline_cache) { - CoglPangoDisplayList *dl = g_new0 (CoglPangoDisplayList, 1); + ClutterPangoDisplayList *dl = g_new0 (ClutterPangoDisplayList, 1); dl->pipeline_cache = pipeline_cache; @@ -108,8 +105,8 @@ _cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache) } static void -_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl, - CoglPangoDisplayListNode *node) +clutter_pango_display_list_append_node (ClutterPangoDisplayList *dl, + PangoDisplayListNode *node) { if (dl->last_node) dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node); @@ -118,34 +115,38 @@ _cogl_pango_display_list_append_node (CoglPangoDisplayList *dl, } void -_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl, - const CoglColor *color) +clutter_pango_display_list_set_color_override (ClutterPangoDisplayList *dl, + const CoglColor *color) { dl->color_override = TRUE; dl->color = *color; } void -_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl) +clutter_pango_display_list_remove_color_override (ClutterPangoDisplayList *dl) { dl->color_override = FALSE; } void -_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, - CoglTexture *texture, - float x_1, float y_1, - float x_2, float y_2, - float tx_1, float ty_1, - float tx_2, float ty_2) +clutter_pango_display_list_add_texture (ClutterPangoDisplayList *dl, + CoglTexture *texture, + float x_1, + float y_1, + float x_2, + float y_2, + float tx_1, + float ty_1, + float tx_2, + float ty_2) { - CoglPangoDisplayListNode *node; - CoglPangoDisplayListRectangle *rectangle; + PangoDisplayListNode *node; + PangoDisplayListRectangle *rectangle; /* Add to the last node if it is a texture node with the same target texture */ if (dl->last_node - && (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE + && (node = dl->last_node->data)->type == PANGO_DISPLAY_LIST_TEXTURE && node->d.texture.texture == texture && (dl->color_override ? (node->color_override && cogl_color_equal (&dl->color, &node->color)) @@ -157,24 +158,24 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, else { /* Otherwise create a new node */ - node = g_new0 (CoglPangoDisplayListNode, 1); + node = g_new0 (PangoDisplayListNode, 1); - node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE; + node->type = PANGO_DISPLAY_LIST_TEXTURE; node->color_override = dl->color_override; node->color = dl->color; node->pipeline = NULL; node->d.texture.texture = g_object_ref (texture); node->d.texture.rectangles - = g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListRectangle)); + = g_array_new (FALSE, FALSE, sizeof (PangoDisplayListRectangle)); node->d.texture.primitive = NULL; - _cogl_pango_display_list_append_node (dl, node); + clutter_pango_display_list_append_node (dl, node); } g_array_set_size (node->d.texture.rectangles, node->d.texture.rectangles->len + 1); rectangle = &g_array_index (node->d.texture.rectangles, - CoglPangoDisplayListRectangle, + PangoDisplayListRectangle, node->d.texture.rectangles->len - 1); rectangle->x_1 = x_1; rectangle->y_1 = y_1; @@ -187,13 +188,15 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, } void -_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, - float x_1, float y_1, - float x_2, float y_2) +clutter_pango_display_list_add_rectangle (ClutterPangoDisplayList *dl, + float x_1, + float y_1, + float x_2, + float y_2) { - CoglPangoDisplayListNode *node = g_new0 (CoglPangoDisplayListNode, 1); + PangoDisplayListNode *node = g_new0 (PangoDisplayListNode, 1); - node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE; + node->type = PANGO_DISPLAY_LIST_RECTANGLE; node->color_override = dl->color_override; node->color = dl->color; node->d.rectangle.x_1 = x_1; @@ -202,20 +205,20 @@ _cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, node->d.rectangle.y_2 = y_2; node->pipeline = NULL; - _cogl_pango_display_list_append_node (dl, node); + clutter_pango_display_list_append_node (dl, node); } void -_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, - float y_1, - float x_11, - float x_21, - float y_2, - float x_12, - float x_22) +clutter_pango_display_list_add_trapezoid (ClutterPangoDisplayList *dl, + float y_1, + float x_11, + float x_21, + float y_2, + float x_12, + float x_22) { CoglContext *ctx = dl->pipeline_cache->ctx; - CoglPangoDisplayListNode *node = g_new0 (CoglPangoDisplayListNode, 1); + PangoDisplayListNode *node = g_new0 (PangoDisplayListNode, 1); CoglVertexP2 vertices[4] = { { x_11, y_1 }, { x_12, y_2 }, @@ -223,7 +226,7 @@ _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, { x_21, y_1 } }; - node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID; + node->type = PANGO_DISPLAY_LIST_TRAPEZOID; node->color_override = dl->color_override; node->color = dl->color; node->pipeline = NULL; @@ -234,13 +237,13 @@ _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, 4, vertices); - _cogl_pango_display_list_append_node (dl, node); + clutter_pango_display_list_append_node (dl, node); } static void emit_rectangles_through_journal (CoglFramebuffer *fb, CoglPipeline *pipeline, - CoglPangoDisplayListNode *node) + PangoDisplayListNode *node) { const float *rectangles = (const float *)node->d.texture.rectangles->data; @@ -253,7 +256,7 @@ emit_rectangles_through_journal (CoglFramebuffer *fb, static void emit_vertex_buffer_geometry (CoglFramebuffer *fb, CoglPipeline *pipeline, - CoglPangoDisplayListNode *node) + PangoDisplayListNode *node) { CoglContext *ctx = cogl_framebuffer_get_context (fb); @@ -297,9 +300,9 @@ emit_vertex_buffer_geometry (CoglFramebuffer *fb, vertices instead of just two */ for (i = 0; i < node->d.texture.rectangles->len; i++) { - const CoglPangoDisplayListRectangle *rectangle + const PangoDisplayListRectangle *rectangle = &g_array_index (node->d.texture.rectangles, - CoglPangoDisplayListRectangle, i); + PangoDisplayListRectangle, i); v->x = rectangle->x_1; v->y = rectangle->y_1; @@ -373,7 +376,7 @@ emit_vertex_buffer_geometry (CoglFramebuffer *fb, static void _cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb, CoglPipeline *pipeline, - CoglPangoDisplayListNode *node) + PangoDisplayListNode *node) { /* For small runs of text like icon labels, we can get better performance * going through the Cogl journal since text may then be batched together @@ -387,30 +390,30 @@ _cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb, } void -cogl_pango_display_list_render (CoglFramebuffer *fb, - CoglPangoDisplayList *dl, - ClutterColorState *color_state, - ClutterColorState *target_color_state, - const CoglColor *color) +clutter_pango_display_list_render (CoglFramebuffer *fb, + ClutterPangoDisplayList *dl, + ClutterColorState *color_state, + ClutterColorState *target_color_state, + const CoglColor *color) { GSList *l; for (l = dl->nodes; l; l = l->next) { - CoglPangoDisplayListNode *node = l->data; + PangoDisplayListNode *node = l->data; CoglColor draw_color; g_autoptr (CoglPipeline) pipeline = NULL; if (node->pipeline == NULL) { - if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) + if (node->type == PANGO_DISPLAY_LIST_TEXTURE) node->pipeline = - _cogl_pango_pipeline_cache_get (dl->pipeline_cache, - node->d.texture.texture); + clutter_pango_pipeline_cache_get (dl->pipeline_cache, + node->d.texture.texture); else node->pipeline = - _cogl_pango_pipeline_cache_get (dl->pipeline_cache, - NULL); + clutter_pango_pipeline_cache_get (dl->pipeline_cache, + NULL); } pipeline = cogl_pipeline_copy (node->pipeline); @@ -437,11 +440,11 @@ cogl_pango_display_list_render (CoglFramebuffer *fb, switch (node->type) { - case COGL_PANGO_DISPLAY_LIST_TEXTURE: + case PANGO_DISPLAY_LIST_TEXTURE: _cogl_framebuffer_draw_display_list_texture (fb, pipeline, node); break; - case COGL_PANGO_DISPLAY_LIST_RECTANGLE: + case PANGO_DISPLAY_LIST_RECTANGLE: cogl_framebuffer_draw_rectangle (fb, pipeline, node->d.rectangle.x_1, @@ -450,7 +453,7 @@ cogl_pango_display_list_render (CoglFramebuffer *fb, node->d.rectangle.y_2); break; - case COGL_PANGO_DISPLAY_LIST_TRAPEZOID: + case PANGO_DISPLAY_LIST_TRAPEZOID: cogl_primitive_draw (node->d.trapezoid.primitive, fb, pipeline); @@ -460,15 +463,15 @@ cogl_pango_display_list_render (CoglFramebuffer *fb, } static void -_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node) +clutter_pango_display_list_node_free (PangoDisplayListNode *node) { - if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) + if (node->type == PANGO_DISPLAY_LIST_TEXTURE) { g_array_free (node->d.texture.rectangles, TRUE); g_clear_object (&node->d.texture.texture); g_clear_object (&node->d.texture.primitive); } - else if (node->type == COGL_PANGO_DISPLAY_LIST_TRAPEZOID) + else if (node->type == PANGO_DISPLAY_LIST_TRAPEZOID) g_clear_object (&node->d.trapezoid.primitive); g_clear_object (&node->pipeline); @@ -477,10 +480,10 @@ _cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node) } void -_cogl_pango_display_list_free (CoglPangoDisplayList *dl) +clutter_pango_display_list_free (ClutterPangoDisplayList *dl) { g_slist_free_full (dl->nodes, (GDestroyNotify) - _cogl_pango_display_list_node_free); + clutter_pango_display_list_node_free); dl->nodes = NULL; dl->last_node = NULL; g_free (dl); diff --git a/clutter/clutter/pango/clutter-pango-display-list.h b/clutter/clutter/pango/clutter-pango-display-list.h new file mode 100644 index 000000000..086ed4910 --- /dev/null +++ b/clutter/clutter/pango/clutter-pango-display-list.h @@ -0,0 +1,89 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2009 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include + +#include "clutter/pango/clutter-pango-pipeline-cache.h" +#include "clutter/clutter-color-state.h" + + +G_BEGIN_DECLS + +typedef struct _ClutterPangoDisplayList ClutterPangoDisplayList; + +ClutterPangoDisplayList * +clutter_pango_display_list_new (ClutterPangoPipelineCache *pipeline_cache); + +void +clutter_pango_display_list_set_color_override (ClutterPangoDisplayList *dl, + const CoglColor *color); + +void +clutter_pango_display_list_remove_color_override (ClutterPangoDisplayList *dl); + +void +clutter_pango_display_list_add_texture (ClutterPangoDisplayList *dl, + CoglTexture *texture, + float x_1, + float y_1, + float x_2, + float y_2, + float tx_1, + float ty_1, + float tx_2, + float ty_2); + +void +clutter_pango_display_list_add_rectangle (ClutterPangoDisplayList *dl, + float x_1, + float y_1, + float x_2, + float y_2); + +void +clutter_pango_display_list_add_trapezoid (ClutterPangoDisplayList *dl, + float y_1, + float x_11, + float x_21, + float y_2, + float x_12, + float x_22); + +void +clutter_pango_display_list_render (CoglFramebuffer *framebuffer, + ClutterPangoDisplayList *dl, + ClutterColorState *color_state, + ClutterColorState *target_color_state, + const CoglColor *color); + +void +clutter_pango_display_list_free (ClutterPangoDisplayList *dl); + +G_END_DECLS diff --git a/clutter/clutter/pango/cogl-pango-glyph-cache.c b/clutter/clutter/pango/clutter-pango-glyph-cache.c similarity index 70% rename from clutter/clutter/pango/cogl-pango-glyph-cache.c rename to clutter/clutter/pango/clutter-pango-glyph-cache.c index 998d40842..41cdbbf47 100644 --- a/clutter/clutter/pango/cogl-pango-glyph-cache.c +++ b/clutter/clutter/pango/clutter-pango-glyph-cache.c @@ -33,12 +33,10 @@ #include #include "clutter/clutter-debug.h" -#include "clutter/pango/cogl-pango-glyph-cache.h" -#include "clutter/pango/cogl-pango-private.h" +#include "clutter/pango/clutter-pango-glyph-cache.h" +#include "clutter/pango/clutter-pango-private.h" -typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey; - -struct _CoglPangoGlyphCache +struct _ClutterPangoGlyphCache { CoglContext *ctx; @@ -50,44 +48,43 @@ struct _CoglPangoGlyphCache GSList *atlases; /* List of callbacks to invoke when an atlas is reorganized */ - GHookList reorganize_callbacks; + GHookList reorganize_callbacks; /* TRUE if we've ever stored a texture in the global atlas. This is used to make sure we only register one callback to listen for global atlas reorganizations */ - gboolean using_global_atlas; + gboolean using_global_atlas; /* True if some of the glyphs are dirty. This is used as an - optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid + optimization in clutter_pango_glyph_cache_set_dirty_glyphs to avoid iterating the hash table if we know none of them are dirty */ - gboolean has_dirty_glyphs; + gboolean has_dirty_glyphs; }; -struct _CoglPangoGlyphCacheKey +typedef struct _PangoGlyphCacheKey { PangoFont *font; - PangoGlyph glyph; -}; + PangoGlyph glyph; +} PangoGlyphCacheKey; static void -cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value) +clutter_pango_glyph_cache_value_free (PangoGlyphCacheValue *value) { g_clear_object (&value->texture); g_free (value); } static void -cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key) +clutter_pango_glyph_cache_key_free (PangoGlyphCacheKey *key) { g_clear_object (&key->font); g_free (key); } static unsigned int -cogl_pango_glyph_cache_hash_func (const void *key) +clutter_pango_glyph_cache_hash_func (const void *key) { - const CoglPangoGlyphCacheKey *cache_key - = (const CoglPangoGlyphCacheKey *) key; + const PangoGlyphCacheKey *cache_key = (const PangoGlyphCacheKey *) key; /* Generate a number affected by both the font and the glyph number. We can safely directly compare the pointers because the @@ -97,36 +94,35 @@ cogl_pango_glyph_cache_hash_func (const void *key) } static gboolean -cogl_pango_glyph_cache_equal_func (const void *a, const void *b) +clutter_pango_glyph_cache_equal_func (const void *a, + const void *b) { - const CoglPangoGlyphCacheKey *key_a - = (const CoglPangoGlyphCacheKey *) a; - const CoglPangoGlyphCacheKey *key_b - = (const CoglPangoGlyphCacheKey *) b; + const PangoGlyphCacheKey *key_a = (const PangoGlyphCacheKey *) a; + const PangoGlyphCacheKey *key_b = (const PangoGlyphCacheKey *) b; /* We can safely directly compare the pointers for the fonts because the key holds a reference to the font so it is not possible that a different font will have the same memory address */ return key_a->font == key_b->font - && key_a->glyph == key_b->glyph; + && key_a->glyph == key_b->glyph; } -CoglPangoGlyphCache * -cogl_pango_glyph_cache_new (CoglContext *ctx) +ClutterPangoGlyphCache * +clutter_pango_glyph_cache_new (CoglContext *ctx) { - CoglPangoGlyphCache *cache; + ClutterPangoGlyphCache *cache; - cache = g_malloc (sizeof (CoglPangoGlyphCache)); + cache = g_malloc (sizeof (ClutterPangoGlyphCache)); /* Note: as a rule we don't take references to a CoglContext * internally since */ cache->ctx = ctx; cache->hash_table = g_hash_table_new_full - (cogl_pango_glyph_cache_hash_func, - cogl_pango_glyph_cache_equal_func, - (GDestroyNotify) cogl_pango_glyph_cache_key_free, - (GDestroyNotify) cogl_pango_glyph_cache_value_free); + (clutter_pango_glyph_cache_hash_func, + clutter_pango_glyph_cache_equal_func, + (GDestroyNotify) clutter_pango_glyph_cache_key_free, + (GDestroyNotify) clutter_pango_glyph_cache_value_free); cache->atlases = NULL; g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook)); @@ -139,21 +135,21 @@ cogl_pango_glyph_cache_new (CoglContext *ctx) } static void -cogl_pango_glyph_cache_reorganize_cb (void *user_data) +clutter_pango_glyph_cache_reorganize_cb (void *user_data) { - CoglPangoGlyphCache *cache = user_data; + ClutterPangoGlyphCache *cache = user_data; g_hook_list_invoke (&cache->reorganize_callbacks, FALSE); } void -cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache) +clutter_pango_glyph_cache_free (ClutterPangoGlyphCache *cache) { if (cache->using_global_atlas) { cogl_atlas_texture_remove_reorganize_callback ( cache->ctx, - cogl_pango_glyph_cache_reorganize_cb, cache); + clutter_pango_glyph_cache_reorganize_cb, cache); } g_slist_foreach (cache->atlases, (GFunc) g_object_unref, NULL); @@ -169,11 +165,11 @@ cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache) } static void -cogl_pango_glyph_cache_update_position_cb (void *user_data, - CoglTexture *new_texture, - const MtkRectangle *rect) +clutter_pango_glyph_cache_update_position_cb (void *user_data, + CoglTexture *new_texture, + const MtkRectangle *rect) { - CoglPangoGlyphCacheValue *value = user_data; + PangoGlyphCacheValue *value = user_data; float tex_width, tex_height; g_clear_object (&value->texture); @@ -195,10 +191,10 @@ cogl_pango_glyph_cache_update_position_cb (void *user_data, } static gboolean -cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache, - PangoFont *font, - PangoGlyph glyph, - CoglPangoGlyphCacheValue *value) +clutter_pango_glyph_cache_add_to_global_atlas (ClutterPangoGlyphCache *cache, + PangoFont *font, + PangoGlyph glyph, + PangoGlyphCacheValue *value) { CoglTexture *texture; GError *ignore_error = NULL; @@ -228,7 +224,7 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache, { cogl_atlas_texture_add_reorganize_callback (cache->ctx, - cogl_pango_glyph_cache_reorganize_cb, cache); + clutter_pango_glyph_cache_reorganize_cb, cache); cache->using_global_atlas = TRUE; } @@ -236,11 +232,11 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache, } static gboolean -cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, - CoglContext *context, - PangoFont *font, - PangoGlyph glyph, - CoglPangoGlyphCacheValue *value) +clutter_pango_glyph_cache_add_to_local_atlas (ClutterPangoGlyphCache *cache, + CoglContext *context, + PangoFont *font, + PangoGlyph glyph, + PangoGlyphCacheValue *value) { CoglAtlas *atlas = NULL; GSList *l; @@ -263,7 +259,7 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, COGL_PIXEL_FORMAT_A_8, COGL_ATLAS_CLEAR_TEXTURE | COGL_ATLAS_DISABLE_MIGRATION, - cogl_pango_glyph_cache_update_position_cb); + clutter_pango_glyph_cache_update_position_cb); CLUTTER_NOTE (PANGO, "Created new atlas for glyphs: %p", atlas); /* If we still can't reserve space then something has gone seriously wrong so we'll just give up */ @@ -277,7 +273,7 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, } cogl_atlas_add_reorganize_callback - (atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache); + (atlas, clutter_pango_glyph_cache_reorganize_cb, NULL, cache); cache->atlases = g_slist_prepend (cache->atlases, atlas); } @@ -285,15 +281,15 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, return TRUE; } -CoglPangoGlyphCacheValue * -cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, - CoglContext *context, - gboolean create, - PangoFont *font, - PangoGlyph glyph) +PangoGlyphCacheValue * +clutter_pango_glyph_cache_lookup (ClutterPangoGlyphCache *cache, + CoglContext *context, + gboolean create, + PangoFont *font, + PangoGlyph glyph) { - CoglPangoGlyphCacheKey lookup_key; - CoglPangoGlyphCacheValue *value; + PangoGlyphCacheKey lookup_key; + PangoGlyphCacheValue *value; lookup_key.font = font; lookup_key.glyph = glyph; @@ -302,10 +298,10 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, if (create && value == NULL) { - CoglPangoGlyphCacheKey *key; + PangoGlyphCacheKey *key; PangoRectangle ink_rect; - value = g_new0 (CoglPangoGlyphCacheValue, 1); + value = g_new0 (PangoGlyphCacheValue, 1); value->texture = NULL; pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); @@ -323,18 +319,18 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, else { /* Try adding the glyph to the global atlas... */ - if (!cogl_pango_glyph_cache_add_to_global_atlas (cache, - font, - glyph, - value) && + if (!clutter_pango_glyph_cache_add_to_global_atlas (cache, + font, + glyph, + value) && /* If it fails try the local atlas */ - !cogl_pango_glyph_cache_add_to_local_atlas (cache, - context, - font, - glyph, - value)) + !clutter_pango_glyph_cache_add_to_local_atlas (cache, + context, + font, + glyph, + value)) { - cogl_pango_glyph_cache_value_free (value); + clutter_pango_glyph_cache_value_free (value); return NULL; } @@ -342,7 +338,7 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, cache->has_dirty_glyphs = TRUE; } - key = g_new0 (CoglPangoGlyphCacheKey, 1); + key = g_new0 (PangoGlyphCacheKey, 1); key->font = g_object_ref (font); key->glyph = glyph; @@ -371,12 +367,12 @@ font_has_color_glyphs (const PangoFont *font) } static void -_cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr, - void *value_ptr, - void *user_data) +clutter_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr, + void *value_ptr, + void *user_data) { - CoglPangoGlyphCacheKey *key = key_ptr; - CoglPangoGlyphCacheValue *value = value_ptr; + PangoGlyphCacheKey *key = key_ptr; + PangoGlyphCacheValue *value = value_ptr; cairo_surface_t *surface; cairo_t *cr; cairo_scaled_font_t *scaled_font; @@ -455,7 +451,7 @@ _cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr, } void -_cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache) +clutter_pango_glyph_cache_set_dirty_glyphs (ClutterPangoGlyphCache *cache) { /* If we know that there are no dirty glyphs then we can shortcut out early */ @@ -463,16 +459,16 @@ _cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache) return; g_hash_table_foreach (cache->hash_table, - _cogl_pango_glyph_cache_set_dirty_glyphs_cb, + clutter_pango_glyph_cache_set_dirty_glyphs_cb, NULL); cache->has_dirty_glyphs = FALSE; } void -_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, - GHookFunc func, - void *user_data) +clutter_pango_glyph_cache_add_reorganize_callback (ClutterPangoGlyphCache *cache, + GHookFunc func, + void *user_data) { GHook *hook = g_hook_alloc (&cache->reorganize_callbacks); hook->func = func; @@ -481,9 +477,9 @@ _cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, } void -_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, - GHookFunc func, - void *user_data) +clutter_pango_glyph_cache_remove_reorganize_callback (ClutterPangoGlyphCache *cache, + GHookFunc func, + void *user_data) { GHook *hook = g_hook_find_func_data (&cache->reorganize_callbacks, FALSE, diff --git a/clutter/clutter/pango/cogl-pango-glyph-cache.h b/clutter/clutter/pango/clutter-pango-glyph-cache.h similarity index 59% rename from clutter/clutter/pango/cogl-pango-glyph-cache.h rename to clutter/clutter/pango/clutter-pango-glyph-cache.h index 1b17e452c..d7c8d3d39 100644 --- a/clutter/clutter/pango/cogl-pango-glyph-cache.h +++ b/clutter/clutter/pango/clutter-pango-glyph-cache.h @@ -35,10 +35,9 @@ G_BEGIN_DECLS -typedef struct _CoglPangoGlyphCache CoglPangoGlyphCache; -typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue; +typedef struct _ClutterPangoGlyphCache ClutterPangoGlyphCache; -struct _CoglPangoGlyphCacheValue +typedef struct { CoglTexture *texture; @@ -60,32 +59,32 @@ struct _CoglPangoGlyphCacheValue guint dirty : 1; /* Set to TRUE if the glyph has colors (eg. emoji) */ guint has_color : 1; -}; +} PangoGlyphCacheValue; -CoglPangoGlyphCache * -cogl_pango_glyph_cache_new (CoglContext *ctx); +ClutterPangoGlyphCache * +clutter_pango_glyph_cache_new (CoglContext *ctx); void -cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache); +clutter_pango_glyph_cache_free (ClutterPangoGlyphCache *cache); -CoglPangoGlyphCacheValue * -cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, - CoglContext *context, - gboolean create, - PangoFont *font, - PangoGlyph glyph); +PangoGlyphCacheValue * +clutter_pango_glyph_cache_lookup (ClutterPangoGlyphCache *cache, + CoglContext *context, + gboolean create, + PangoFont *font, + PangoGlyph glyph); void -_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, - GHookFunc func, - void *user_data); +clutter_pango_glyph_cache_add_reorganize_callback (ClutterPangoGlyphCache *cache, + GHookFunc func, + void *user_data); void -_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, - GHookFunc func, - void *user_data); +clutter_pango_glyph_cache_remove_reorganize_callback (ClutterPangoGlyphCache *cache, + GHookFunc func, + void *user_data); void -_cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache); +clutter_pango_glyph_cache_set_dirty_glyphs (ClutterPangoGlyphCache *cache); G_END_DECLS diff --git a/clutter/clutter/pango/cogl-pango-pipeline-cache.c b/clutter/clutter/pango/clutter-pango-pipeline-cache.c similarity index 83% rename from clutter/clutter/pango/cogl-pango-pipeline-cache.c rename to clutter/clutter/pango/clutter-pango-pipeline-cache.c index 4beeb596b..582db319e 100644 --- a/clutter/clutter/pango/cogl-pango-pipeline-cache.c +++ b/clutter/clutter/pango/clutter-pango-pipeline-cache.c @@ -35,13 +35,11 @@ #include -#include "clutter/pango/cogl-pango-pipeline-cache.h" - -typedef struct _CoglPangoPipelineCacheEntry CoglPangoPipelineCacheEntry; +#include "clutter/pango/clutter-pango-pipeline-cache.h" static GQuark pipeline_destroy_notify_key = 0; -struct _CoglPangoPipelineCacheEntry +typedef struct _PangoPipelineCacheEntry { /* This will take a reference or it can be NULL to represent the pipeline used to render colors */ @@ -49,19 +47,19 @@ struct _CoglPangoPipelineCacheEntry /* This will only take a weak reference */ CoglPipeline *pipeline; -}; +} PangoPipelineCacheEntry; static void -_cogl_pango_pipeline_cache_key_destroy (void *data) +clutter_pango_pipeline_cache_key_destroy (void *data) { if (data) g_object_unref (data); } static void -_cogl_pango_pipeline_cache_value_destroy (void *data) +clutter_pango_pipeline_cache_value_destroy (void *data) { - CoglPangoPipelineCacheEntry *cache_entry = data; + PangoPipelineCacheEntry *cache_entry = data; g_clear_object (&cache_entry->texture); @@ -71,10 +69,10 @@ _cogl_pango_pipeline_cache_value_destroy (void *data) g_free (cache_entry); } -CoglPangoPipelineCache * -_cogl_pango_pipeline_cache_new (CoglContext *ctx) +ClutterPangoPipelineCache * +clutter_pango_pipeline_cache_new (CoglContext *ctx) { - CoglPangoPipelineCache *cache = g_new (CoglPangoPipelineCache, 1); + ClutterPangoPipelineCache *cache = g_new (ClutterPangoPipelineCache, 1); cache->ctx = g_object_ref (ctx); @@ -84,8 +82,8 @@ _cogl_pango_pipeline_cache_new (CoglContext *ctx) cache->hash_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, - _cogl_pango_pipeline_cache_key_destroy, - _cogl_pango_pipeline_cache_value_destroy); + clutter_pango_pipeline_cache_key_destroy, + clutter_pango_pipeline_cache_value_destroy); cache->base_texture_rgba_pipeline = NULL; cache->base_texture_alpha_pipeline = NULL; @@ -94,7 +92,7 @@ _cogl_pango_pipeline_cache_new (CoglContext *ctx) } static CoglPipeline * -get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache) +get_base_texture_rgba_pipeline (ClutterPangoPipelineCache *cache) { if (cache->base_texture_rgba_pipeline == NULL) { @@ -112,7 +110,7 @@ get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache) } static CoglPipeline * -get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache) +get_base_texture_alpha_pipeline (ClutterPangoPipelineCache *cache) { if (cache->base_texture_alpha_pipeline == NULL) { @@ -146,7 +144,7 @@ get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache) typedef struct { - CoglPangoPipelineCache *cache; + ClutterPangoPipelineCache *cache; CoglTexture *texture; } PipelineDestroyNotifyData; @@ -160,12 +158,12 @@ pipeline_destroy_notify_cb (void *user_data) } CoglPipeline * -_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, - CoglTexture *texture) +clutter_pango_pipeline_cache_get (ClutterPangoPipelineCache *cache, + CoglTexture *texture) { - CoglPangoPipelineCacheEntry *entry; + PangoPipelineCacheEntry *entry; PipelineDestroyNotifyData *destroy_data; - pipeline_destroy_notify_key = g_quark_from_static_string ("-cogl-pango-pipeline-cache-key"); + pipeline_destroy_notify_key = g_quark_from_static_string ("-clutter-pango-pipeline-cache-key"); /* Look for an existing entry */ entry = g_hash_table_lookup (cache->hash_table, texture); @@ -174,7 +172,7 @@ _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, return g_object_ref (entry->pipeline); /* No existing pipeline was found so let's create another */ - entry = g_new0 (CoglPangoPipelineCacheEntry, 1); + entry = g_new0 (PangoPipelineCacheEntry, 1); if (texture) { @@ -218,7 +216,7 @@ _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, } void -_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache) +clutter_pango_pipeline_cache_free (ClutterPangoPipelineCache *cache) { g_clear_object (&cache->base_texture_rgba_pipeline); g_clear_object (&cache->base_texture_alpha_pipeline); diff --git a/clutter/clutter/pango/cogl-pango-pipeline-cache.h b/clutter/clutter/pango/clutter-pango-pipeline-cache.h similarity index 83% rename from clutter/clutter/pango/cogl-pango-pipeline-cache.h rename to clutter/clutter/pango/clutter-pango-pipeline-cache.h index f892951f8..2133bd0d2 100644 --- a/clutter/clutter/pango/cogl-pango-pipeline-cache.h +++ b/clutter/clutter/pango/clutter-pango-pipeline-cache.h @@ -39,7 +39,7 @@ G_BEGIN_DECLS -typedef struct _CoglPangoPipelineCache +typedef struct { CoglContext *ctx; @@ -47,20 +47,20 @@ typedef struct _CoglPangoPipelineCache CoglPipeline *base_texture_alpha_pipeline; CoglPipeline *base_texture_rgba_pipeline; -} CoglPangoPipelineCache; +} ClutterPangoPipelineCache; -CoglPangoPipelineCache * -_cogl_pango_pipeline_cache_new (CoglContext *ctx); +ClutterPangoPipelineCache * +clutter_pango_pipeline_cache_new (CoglContext *ctx); /* Returns a pipeline that can be used to render glyphs in the given texture. The pipeline has a new reference so it is up to the caller to unref it */ CoglPipeline * -_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, - CoglTexture *texture); +clutter_pango_pipeline_cache_get (ClutterPangoPipelineCache *cache, + CoglTexture *texture); void -_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache); +clutter_pango_pipeline_cache_free (ClutterPangoPipelineCache *cache); G_END_DECLS diff --git a/clutter/clutter/pango/cogl-pango-private.h b/clutter/clutter/pango/clutter-pango-private.h similarity index 98% rename from clutter/clutter/pango/cogl-pango-private.h rename to clutter/clutter/pango/clutter-pango-private.h index 9876616eb..ff43a304d 100644 --- a/clutter/clutter/pango/cogl-pango-private.h +++ b/clutter/clutter/pango/clutter-pango-private.h @@ -43,7 +43,7 @@ G_BEGIN_DECLS PangoRenderer * -_cogl_pango_renderer_new (CoglContext *context); +clutter_pango_renderer_new (CoglContext *context); /** * clutter_ensure_glyph_cache_for_layout: diff --git a/clutter/clutter/pango/clutter-pango-render.c b/clutter/clutter/pango/clutter-pango-render.c new file mode 100644 index 000000000..c99ca954d --- /dev/null +++ b/clutter/clutter/pango/clutter-pango-render.c @@ -0,0 +1,655 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2008 OpenedHand + * Copyright (C) 2012 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + * Authors: + * Neil Roberts + * Robert Bragg + * Matthew Allum + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "clutter/clutter-debug.h" +#include "clutter/clutter-context-private.h" +#include "clutter/clutter-private.h" +#include "clutter/pango/clutter-pango-private.h" +#include "clutter/pango/clutter-pango-glyph-cache.h" +#include "clutter/pango/clutter-pango-display-list.h" +#include "cogl/cogl.h" + +#define PANGO_UNKNOWN_GLYPH_WIDTH 10 +#define PANGO_UNKNOWN_GLYPH_HEIGHT 14 + +enum +{ + PROP_0, + + PROP_COGL_CONTEXT, + PROP_LAST +}; + +struct _ClutterPangoRenderer +{ + PangoRenderer parent_instance; + + CoglContext *ctx; + + ClutterPangoGlyphCache *glyph_cache; + ClutterPangoPipelineCache *pipeline_cache; + + /* The current display list that is being built */ + ClutterPangoDisplayList *display_list; +}; + +G_DECLARE_FINAL_TYPE (ClutterPangoRenderer, + clutter_pango_renderer, + CLUTTER_PANGO, + RENDERER, + PangoRenderer) + +G_DEFINE_FINAL_TYPE (ClutterPangoRenderer, clutter_pango_renderer, PANGO_TYPE_RENDERER); + +/* An instance of this struct gets attached to each PangoLayout to + cache the VBO and to detect changes to the layout */ +typedef struct _PangoLayoutQdata +{ + ClutterPangoRenderer *renderer; + /* The cache of the geometry for the layout */ + ClutterPangoDisplayList *display_list; + /* A reference to the first line of the layout. This is just used to + detect changes */ + PangoLayoutLine *first_line; +} PangoLayoutQdata; + +typedef struct +{ + ClutterPangoDisplayList *display_list; + float x1, y1, x2, y2; +} PangoRendererSliceCbData; + +PangoRenderer * +clutter_pango_renderer_new (CoglContext *context) +{ + return PANGO_RENDERER (g_object_new (clutter_pango_renderer_get_type (), + "context", context, NULL)); +} + +static void +clutter_pango_renderer_slice_cb (CoglTexture *texture, + const float *slice_coords, + const float *virtual_coords, + void *user_data) +{ + PangoRendererSliceCbData *data = user_data; + + /* Note: this assumes that there is only one slice containing the + whole texture and it doesn't attempt to split up the vertex + coordinates based on the virtual_coords */ + + clutter_pango_display_list_add_texture (data->display_list, + texture, + data->x1, + data->y1, + data->x2, + data->y2, + slice_coords[0], + slice_coords[1], + slice_coords[2], + slice_coords[3]); +} + +static void +clutter_pango_renderer_draw_glyph (ClutterPangoRenderer *renderer, + PangoGlyphCacheValue *cache_value, + float x1, + float y1) +{ + PangoRendererSliceCbData data; + + g_return_if_fail (renderer->display_list != NULL); + + data.display_list = renderer->display_list; + data.x1 = x1; + data.y1 = y1; + data.x2 = x1 + (float) cache_value->draw_width; + data.y2 = y1 + (float) cache_value->draw_height; + + /* We iterate the internal sub textures of the texture so that we + can get a pointer to the base texture even if the texture is in + the global atlas. That way the display list can recognise that + the neighbouring glyphs are coming from the same atlas and bundle + them together into a single VBO */ + + cogl_meta_texture_foreach_in_region (cache_value->texture, + cache_value->tx1, + cache_value->ty1, + cache_value->tx2, + cache_value->ty2, + COGL_PIPELINE_WRAP_MODE_REPEAT, + COGL_PIPELINE_WRAP_MODE_REPEAT, + clutter_pango_renderer_slice_cb, + &data); +} + +static void +clutter_pango_renderer_init (ClutterPangoRenderer *renderer) +{ +} + +static void +clutter_pango_renderer_constructed (GObject *gobject) +{ + ClutterPangoRenderer *renderer = CLUTTER_PANGO_RENDERER (gobject); + CoglContext *ctx = renderer->ctx; + + renderer->pipeline_cache = clutter_pango_pipeline_cache_new (ctx); + renderer->glyph_cache = clutter_pango_glyph_cache_new (ctx); + + G_OBJECT_CLASS (clutter_pango_renderer_parent_class)->constructed (gobject); +} + +static void +clutter_pango_renderer_set_property (GObject *object, + unsigned int prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterPangoRenderer *renderer = CLUTTER_PANGO_RENDERER (object); + + switch (prop_id) + { + case PROP_COGL_CONTEXT: + renderer->ctx = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clutter_pango_renderer_dispose (GObject *object) +{ + ClutterPangoRenderer *renderer = CLUTTER_PANGO_RENDERER (object); + + g_clear_object (&renderer->ctx); + + G_OBJECT_CLASS (clutter_pango_renderer_parent_class)->dispose (object); +} + +static void +clutter_pango_renderer_finalize (GObject *object) +{ + ClutterPangoRenderer *renderer = CLUTTER_PANGO_RENDERER (object); + + clutter_pango_glyph_cache_free (renderer->glyph_cache); + clutter_pango_pipeline_cache_free (renderer->pipeline_cache); + + G_OBJECT_CLASS (clutter_pango_renderer_parent_class)->finalize (object); +} + +static GQuark +clutter_pango_layout_get_qdata_key (void) +{ + static GQuark key = 0; + + if (G_UNLIKELY (key == 0)) + key = g_quark_from_static_string ("ClutterPangoDisplayList"); + + return key; +} + +static void +clutter_pango_layout_qdata_forget_display_list (PangoLayoutQdata *qdata) +{ + if (qdata->display_list) + { + clutter_pango_glyph_cache_remove_reorganize_callback + (qdata->renderer->glyph_cache, + (GHookFunc) clutter_pango_layout_qdata_forget_display_list, + qdata); + + clutter_pango_display_list_free (qdata->display_list); + + qdata->display_list = NULL; + } +} + +static void +clutter_pango_render_qdata_destroy (PangoLayoutQdata *qdata) +{ + clutter_pango_layout_qdata_forget_display_list (qdata); + if (qdata->first_line) + pango_layout_line_unref (qdata->first_line); + g_free (qdata); +} + +void +clutter_show_layout (CoglFramebuffer *fb, + PangoLayout *layout, + float x, + float y, + const CoglColor *color, + ClutterColorState *color_state, + ClutterColorState *target_color_state) +{ + ClutterPangoRenderer *renderer; + PangoLayoutQdata *qdata; + ClutterContext *context; + + context = _clutter_context_get_default (); + renderer = CLUTTER_PANGO_RENDERER (clutter_context_get_font_renderer (context)); + if (G_UNLIKELY (!renderer)) + return; + + qdata = g_object_get_qdata (G_OBJECT (layout), + clutter_pango_layout_get_qdata_key ()); + + if (qdata == NULL) + { + qdata = g_new0 (PangoLayoutQdata, 1); + qdata->renderer = renderer; + g_object_set_qdata_full (G_OBJECT (layout), + clutter_pango_layout_get_qdata_key (), + qdata, + (GDestroyNotify) + clutter_pango_render_qdata_destroy); + } + + /* Check if the layout has changed since the last build of the + display list. This trick was suggested by Behdad Esfahbod here: + http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html */ + if (qdata->display_list && + ((qdata->first_line && + qdata->first_line->layout != layout))) + clutter_pango_layout_qdata_forget_display_list (qdata); + + if (qdata->display_list == NULL) + { + clutter_ensure_glyph_cache_for_layout (layout); + + qdata->display_list = + clutter_pango_display_list_new (renderer->pipeline_cache); + + /* Register for notification of when the glyph cache changes so + we can rebuild the display list */ + clutter_pango_glyph_cache_add_reorganize_callback + (renderer->glyph_cache, + (GHookFunc) clutter_pango_layout_qdata_forget_display_list, + qdata); + + renderer->display_list = qdata->display_list; + pango_renderer_draw_layout (PANGO_RENDERER (renderer), layout, 0, 0); + renderer->display_list = NULL; + } + + cogl_framebuffer_push_matrix (fb); + cogl_framebuffer_translate (fb, x, y, 0); + + clutter_pango_display_list_render (fb, + qdata->display_list, + color_state, target_color_state, + color); + + cogl_framebuffer_pop_matrix (fb); + + /* Keep a reference to the first line of the layout so we can detect + changes */ + if (qdata->first_line) + { + pango_layout_line_unref (qdata->first_line); + qdata->first_line = NULL; + } + if (pango_layout_get_line_count (layout) > 0) + { + qdata->first_line = pango_layout_get_line (layout, 0); + pango_layout_line_ref (qdata->first_line); + } +} + +static PangoGlyphCacheValue * +clutter_pango_renderer_get_cached_glyph (PangoRenderer *renderer, + gboolean create, + PangoFont *font, + PangoGlyph glyph) +{ + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + + return clutter_pango_glyph_cache_lookup (priv->glyph_cache, + priv->ctx, + create, font, glyph); +} + +static void +clutter_pango_ensure_glyph_cache_for_layout_line_internal (PangoLayoutLine *line) +{ + ClutterContext *context; + PangoRenderer *renderer; + GSList *l; + + context = _clutter_context_get_default (); + renderer = clutter_context_get_font_renderer (context); + + for (l = line->runs; l; l = l->next) + { + PangoLayoutRun *run = l->data; + PangoGlyphString *glyphs = run->glyphs; + int i; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *gi = &glyphs->glyphs[i]; + + /* If the glyph isn't cached then this will reserve + space for it now. We won't actually draw the glyph + yet because reserving space could cause all of the + other glyphs to be moved so we might as well redraw + them all later once we know that the position is + settled */ + clutter_pango_renderer_get_cached_glyph (renderer, TRUE, + run->item->analysis.font, + gi->glyph); + } + } +} + +void +clutter_ensure_glyph_cache_for_layout (PangoLayout *layout) +{ + ClutterContext *context; + ClutterPangoRenderer *renderer; + PangoLayoutIter *iter; + + context = _clutter_context_get_default (); + renderer = CLUTTER_PANGO_RENDERER (clutter_context_get_font_renderer (context)); + + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + + if ((iter = pango_layout_get_iter (layout)) == NULL) + return; + + do + { + PangoLayoutLine *line; + + line = pango_layout_iter_get_line_readonly (iter); + + clutter_pango_ensure_glyph_cache_for_layout_line_internal (line); + } + while (pango_layout_iter_next_line (iter)); + + pango_layout_iter_free (iter); + + /* Now that we know all of the positions are settled we'll fill in + any dirty glyphs */ + clutter_pango_glyph_cache_set_dirty_glyphs (renderer->glyph_cache); +} + +static void +clutter_pango_renderer_set_color_for_part (PangoRenderer *renderer, + PangoRenderPart part) +{ + PangoColor *pango_color = pango_renderer_get_color (renderer, part); + uint16_t alpha = pango_renderer_get_alpha (renderer, part); + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + + if (pango_color) + { + CoglColor color; + + cogl_color_init_from_4f (&color, + pango_color->red / 65535.0f, + pango_color->green / 65535.0f, + pango_color->blue / 65535.0f, + alpha ? alpha / 65535.0f : 1.0f); + + clutter_pango_display_list_set_color_override (priv->display_list, &color); + } + else + clutter_pango_display_list_remove_color_override (priv->display_list); +} + +static void +clutter_pango_renderer_draw_box (PangoRenderer *renderer, + int x, + int y, + int width, + int height) +{ + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + + g_return_if_fail (priv->display_list != NULL); + + clutter_pango_display_list_add_rectangle (priv->display_list, + x, + y - height, + x + width, + y); +} + +static void +clutter_pango_renderer_get_device_units (PangoRenderer *renderer, + int xin, + int yin, + float *xout, + float *yout) +{ + const PangoMatrix *matrix; + + if ((matrix = pango_renderer_get_matrix (renderer))) + { + /* Convert user-space coords to device coords */ + *xout = (float) ((xin * matrix->xx + yin * matrix->xy) / + PANGO_SCALE + matrix->x0); + *yout = (float) ((yin * matrix->yy + xin * matrix->yx) / + PANGO_SCALE + matrix->y0); + } + else + { + *xout = PANGO_PIXELS (xin); + *yout = PANGO_PIXELS (yin); + } +} + +static void +clutter_pango_renderer_draw_rectangle (PangoRenderer *renderer, + PangoRenderPart part, + int x, + int y, + int width, + int height) +{ + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + float x1, x2, y1, y2; + + g_return_if_fail (priv->display_list != NULL); + + clutter_pango_renderer_set_color_for_part (renderer, part); + + clutter_pango_renderer_get_device_units (renderer, + x, y, + &x1, &y1); + clutter_pango_renderer_get_device_units (renderer, + x + width, y + height, + &x2, &y2); + + clutter_pango_display_list_add_rectangle (priv->display_list, + x1, y1, x2, y2); +} + +static void +clutter_pango_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22) +{ + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + + g_return_if_fail (priv->display_list != NULL); + + clutter_pango_renderer_set_color_for_part (renderer, part); + + clutter_pango_display_list_add_trapezoid (priv->display_list, + (float) y1, + (float) x11, + (float) x21, + (float) y2, + (float) x12, + (float) x22); +} + +static void +clutter_pango_renderer_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int xi, + int yi) +{ + ClutterPangoRenderer *priv = CLUTTER_PANGO_RENDERER (renderer); + PangoGlyphCacheValue *cache_value; + int i; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *gi = glyphs->glyphs + i; + float x, y; + + clutter_pango_renderer_set_color_for_part (renderer, + PANGO_RENDER_PART_FOREGROUND); + clutter_pango_renderer_get_device_units (renderer, + xi + gi->geometry.x_offset, + yi + gi->geometry.y_offset, + &x, &y); + + if ((gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)) + { + if (font == NULL) + { + clutter_pango_renderer_draw_box (renderer, + (int) x, + (int) y, + PANGO_UNKNOWN_GLYPH_WIDTH, + PANGO_UNKNOWN_GLYPH_HEIGHT); + } + else + { + PangoRectangle ink_rect; + + pango_font_get_glyph_extents (font, gi->glyph, &ink_rect, NULL); + pango_extents_to_pixels (&ink_rect, NULL); + + clutter_pango_renderer_draw_box (renderer, + (int) (x + ink_rect.x), + (int) (y + ink_rect.y + ink_rect.height), + ink_rect.width, + ink_rect.height); + } + } + else + { + /* Get the texture containing the glyph */ + cache_value = + clutter_pango_renderer_get_cached_glyph (renderer, + FALSE, + font, + gi->glyph); + + /* clutter_ensure_glyph_cache_for_layout should always be + called before rendering a layout so we should never have + a dirty glyph here */ + g_assert (cache_value == NULL || !cache_value->dirty); + + if (cache_value == NULL) + { + clutter_pango_renderer_draw_box (renderer, + (int) x, + (int) y, + PANGO_UNKNOWN_GLYPH_WIDTH, + PANGO_UNKNOWN_GLYPH_HEIGHT); + } + else if (cache_value->texture) + { + x += (float)(cache_value->draw_x); + y += (float)(cache_value->draw_y); + + /* Do not override color if the glyph/font provide its own */ + if (cache_value->has_color) + { + CoglColor color; + uint16_t alpha; + + alpha = pango_renderer_get_alpha (renderer, + PANGO_RENDER_PART_FOREGROUND); + cogl_color_init_from_4f (&color, 1.0f, 1.0f, 1.0f, + alpha ? (alpha >> 8) / 255.0f : 1.0f); + clutter_pango_display_list_set_color_override (priv->display_list, &color); + } + + clutter_pango_renderer_draw_glyph (priv, cache_value, x, y); + } + } + + xi += gi->geometry.width; + } +} + +static void +clutter_pango_renderer_class_init (ClutterPangoRendererClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); + GParamSpec *pspec; + + object_class->set_property = clutter_pango_renderer_set_property; + object_class->constructed = clutter_pango_renderer_constructed; + object_class->dispose = clutter_pango_renderer_dispose; + object_class->finalize = clutter_pango_renderer_finalize; + + pspec = g_param_spec_object ("context", NULL, NULL, + COGL_TYPE_CONTEXT, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_property (object_class, PROP_COGL_CONTEXT, pspec); + + renderer_class->draw_glyphs = clutter_pango_renderer_draw_glyphs; + renderer_class->draw_rectangle = clutter_pango_renderer_draw_rectangle; + renderer_class->draw_trapezoid = clutter_pango_renderer_draw_trapezoid; +} diff --git a/clutter/clutter/pango/cogl-pango-display-list.h b/clutter/clutter/pango/cogl-pango-display-list.h deleted file mode 100644 index bc91f4a43..000000000 --- a/clutter/clutter/pango/cogl-pango-display-list.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Copyright (C) 2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include - -#include "clutter/pango/cogl-pango-pipeline-cache.h" -#include "clutter/pango/cogl-pango-private.h" - - -G_BEGIN_DECLS - -typedef struct _CoglPangoDisplayList CoglPangoDisplayList; - -CoglPangoDisplayList * -_cogl_pango_display_list_new (CoglPangoPipelineCache *); - -void -_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl, - const CoglColor *color); - -void -_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl); - -void -_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, - CoglTexture *texture, - float x_1, float y_1, - float x_2, float y_2, - float tx_1, float ty_1, - float tx_2, float ty_2); - -void -_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, - float x_1, float y_1, - float x_2, float y_2); - -void -_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, - float y_1, - float x_11, - float x_21, - float y_2, - float x_12, - float x_22); - -void -cogl_pango_display_list_render (CoglFramebuffer *framebuffer, - CoglPangoDisplayList *dl, - ClutterColorState *color_state, - ClutterColorState *target_color_state, - const CoglColor *color); - -void -_cogl_pango_display_list_free (CoglPangoDisplayList *dl); - -G_END_DECLS diff --git a/clutter/clutter/pango/cogl-pango-render.c b/clutter/clutter/pango/cogl-pango-render.c deleted file mode 100644 index b81a577f2..000000000 --- a/clutter/clutter/pango/cogl-pango-render.c +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Copyright (C) 2008 OpenedHand - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * Authors: - * Neil Roberts - * Robert Bragg - * Matthew Allum - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "clutter/clutter-debug.h" -#include "clutter/clutter-context-private.h" -#include "clutter/clutter-private.h" -#include "clutter/pango/cogl-pango-private.h" -#include "clutter/pango/cogl-pango-glyph-cache.h" -#include "clutter/pango/cogl-pango-display-list.h" -#include "cogl/cogl.h" - -#define PANGO_UNKNOWN_GLYPH_WIDTH 10 -#define PANGO_UNKNOWN_GLYPH_HEIGHT 14 - -enum -{ - PROP_0, - - PROP_COGL_CONTEXT, - PROP_LAST -}; - -struct _CoglPangoRenderer -{ - PangoRenderer parent_instance; - - CoglContext *ctx; - - CoglPangoGlyphCache *glyph_cache; - CoglPangoPipelineCache *pipeline_cache; - - /* The current display list that is being built */ - CoglPangoDisplayList *display_list; -}; - -G_DECLARE_FINAL_TYPE (CoglPangoRenderer, - cogl_pango_renderer, - COGL_PANGO, - RENDERER, - PangoRenderer) - - -G_DEFINE_FINAL_TYPE (CoglPangoRenderer, cogl_pango_renderer, PANGO_TYPE_RENDERER); - -/* An instance of this struct gets attached to each PangoLayout to - cache the VBO and to detect changes to the layout */ -typedef struct _CoglPangoLayoutQdata -{ - CoglPangoRenderer *renderer; - /* The cache of the geometry for the layout */ - CoglPangoDisplayList *display_list; - /* A reference to the first line of the layout. This is just used to - detect changes */ - PangoLayoutLine *first_line; -} CoglPangoLayoutQdata; - -typedef struct -{ - CoglPangoDisplayList *display_list; - float x1, y1, x2, y2; -} CoglPangoRendererSliceCbData; - -PangoRenderer * -_cogl_pango_renderer_new (CoglContext *context) -{ - return PANGO_RENDERER (g_object_new (cogl_pango_renderer_get_type (), - "context", context, NULL)); -} - -static void -cogl_pango_renderer_slice_cb (CoglTexture *texture, - const float *slice_coords, - const float *virtual_coords, - void *user_data) -{ - CoglPangoRendererSliceCbData *data = user_data; - - /* Note: this assumes that there is only one slice containing the - whole texture and it doesn't attempt to split up the vertex - coordinates based on the virtual_coords */ - - _cogl_pango_display_list_add_texture (data->display_list, - texture, - data->x1, - data->y1, - data->x2, - data->y2, - slice_coords[0], - slice_coords[1], - slice_coords[2], - slice_coords[3]); -} - -static void -cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv, - CoglPangoGlyphCacheValue *cache_value, - float x1, - float y1) -{ - CoglPangoRendererSliceCbData data; - - g_return_if_fail (priv->display_list != NULL); - - data.display_list = priv->display_list; - data.x1 = x1; - data.y1 = y1; - data.x2 = x1 + (float) cache_value->draw_width; - data.y2 = y1 + (float) cache_value->draw_height; - - /* We iterate the internal sub textures of the texture so that we - can get a pointer to the base texture even if the texture is in - the global atlas. That way the display list can recognise that - the neighbouring glyphs are coming from the same atlas and bundle - them together into a single VBO */ - - cogl_meta_texture_foreach_in_region (cache_value->texture, - cache_value->tx1, - cache_value->ty1, - cache_value->tx2, - cache_value->ty2, - COGL_PIPELINE_WRAP_MODE_REPEAT, - COGL_PIPELINE_WRAP_MODE_REPEAT, - cogl_pango_renderer_slice_cb, - &data); -} - -static void -cogl_pango_renderer_init (CoglPangoRenderer *priv) -{ -} - -static void -_cogl_pango_renderer_constructed (GObject *gobject) -{ - CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (gobject); - CoglContext *ctx = renderer->ctx; - - renderer->pipeline_cache = _cogl_pango_pipeline_cache_new (ctx); - renderer->glyph_cache = cogl_pango_glyph_cache_new (ctx); - - G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->constructed (gobject); -} - -static void -cogl_pango_renderer_set_property (GObject *object, - unsigned int prop_id, - const GValue *value, - GParamSpec *pspec) -{ - CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (object); - - switch (prop_id) - { - case PROP_COGL_CONTEXT: - renderer->ctx = g_value_get_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -cogl_pango_renderer_dispose (GObject *object) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); - - g_clear_object (&priv->ctx); - - G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->dispose (object); -} - -static void -cogl_pango_renderer_finalize (GObject *object) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); - - cogl_pango_glyph_cache_free (priv->glyph_cache); - _cogl_pango_pipeline_cache_free (priv->pipeline_cache); - - G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object); -} - -static GQuark -cogl_pango_layout_get_qdata_key (void) -{ - static GQuark key = 0; - - if (G_UNLIKELY (key == 0)) - key = g_quark_from_static_string ("CoglPangoDisplayList"); - - return key; -} - -static void -cogl_pango_layout_qdata_forget_display_list (CoglPangoLayoutQdata *qdata) -{ - if (qdata->display_list) - { - _cogl_pango_glyph_cache_remove_reorganize_callback - (qdata->renderer->glyph_cache, - (GHookFunc) cogl_pango_layout_qdata_forget_display_list, - qdata); - - _cogl_pango_display_list_free (qdata->display_list); - - qdata->display_list = NULL; - } -} - -static void -cogl_pango_render_qdata_destroy (CoglPangoLayoutQdata *qdata) -{ - cogl_pango_layout_qdata_forget_display_list (qdata); - if (qdata->first_line) - pango_layout_line_unref (qdata->first_line); - g_free (qdata); -} - -void -clutter_show_layout (CoglFramebuffer *fb, - PangoLayout *layout, - float x, - float y, - const CoglColor *color, - ClutterColorState *color_state, - ClutterColorState *target_color_state) -{ - CoglPangoRenderer *renderer; - CoglPangoLayoutQdata *qdata; - ClutterContext *context; - - context = _clutter_context_get_default (); - renderer = COGL_PANGO_RENDERER (clutter_context_get_font_renderer (context)); - if (G_UNLIKELY (!renderer)) - return; - - qdata = g_object_get_qdata (G_OBJECT (layout), - cogl_pango_layout_get_qdata_key ()); - - if (qdata == NULL) - { - qdata = g_new0 (CoglPangoLayoutQdata, 1); - qdata->renderer = renderer; - g_object_set_qdata_full (G_OBJECT (layout), - cogl_pango_layout_get_qdata_key (), - qdata, - (GDestroyNotify) - cogl_pango_render_qdata_destroy); - } - - /* Check if the layout has changed since the last build of the - display list. This trick was suggested by Behdad Esfahbod here: - http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html */ - if (qdata->display_list && - ((qdata->first_line && - qdata->first_line->layout != layout))) - cogl_pango_layout_qdata_forget_display_list (qdata); - - if (qdata->display_list == NULL) - { - clutter_ensure_glyph_cache_for_layout (layout); - - qdata->display_list = - _cogl_pango_display_list_new (renderer->pipeline_cache); - - /* Register for notification of when the glyph cache changes so - we can rebuild the display list */ - _cogl_pango_glyph_cache_add_reorganize_callback - (renderer->glyph_cache, - (GHookFunc) cogl_pango_layout_qdata_forget_display_list, - qdata); - - renderer->display_list = qdata->display_list; - pango_renderer_draw_layout (PANGO_RENDERER (renderer), layout, 0, 0); - renderer->display_list = NULL; - } - - cogl_framebuffer_push_matrix (fb); - cogl_framebuffer_translate (fb, x, y, 0); - - cogl_pango_display_list_render (fb, - qdata->display_list, - color_state, target_color_state, - color); - - cogl_framebuffer_pop_matrix (fb); - - /* Keep a reference to the first line of the layout so we can detect - changes */ - if (qdata->first_line) - { - pango_layout_line_unref (qdata->first_line); - qdata->first_line = NULL; - } - if (pango_layout_get_line_count (layout) > 0) - { - qdata->first_line = pango_layout_get_line (layout, 0); - pango_layout_line_ref (qdata->first_line); - } -} - -static CoglPangoGlyphCacheValue * -cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer, - gboolean create, - PangoFont *font, - PangoGlyph glyph) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - - return cogl_pango_glyph_cache_lookup (priv->glyph_cache, - priv->ctx, - create, font, glyph); -} - -static void -_cogl_pango_ensure_glyph_cache_for_layout_line_internal (PangoLayoutLine *line) -{ - ClutterContext *context; - PangoRenderer *renderer; - GSList *l; - - context = _clutter_context_get_default (); - renderer = clutter_context_get_font_renderer (context); - - for (l = line->runs; l; l = l->next) - { - PangoLayoutRun *run = l->data; - PangoGlyphString *glyphs = run->glyphs; - int i; - - for (i = 0; i < glyphs->num_glyphs; i++) - { - PangoGlyphInfo *gi = &glyphs->glyphs[i]; - - /* If the glyph isn't cached then this will reserve - space for it now. We won't actually draw the glyph - yet because reserving space could cause all of the - other glyphs to be moved so we might as well redraw - them all later once we know that the position is - settled */ - cogl_pango_renderer_get_cached_glyph (renderer, TRUE, - run->item->analysis.font, - gi->glyph); - } - } -} - -void -clutter_ensure_glyph_cache_for_layout (PangoLayout *layout) -{ - ClutterContext *context; - CoglPangoRenderer *renderer; - PangoLayoutIter *iter; - - context = _clutter_context_get_default (); - renderer = COGL_PANGO_RENDERER (clutter_context_get_font_renderer (context)); - - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - if ((iter = pango_layout_get_iter (layout)) == NULL) - return; - - do - { - PangoLayoutLine *line; - - line = pango_layout_iter_get_line_readonly (iter); - - _cogl_pango_ensure_glyph_cache_for_layout_line_internal (line); - } - while (pango_layout_iter_next_line (iter)); - - pango_layout_iter_free (iter); - - /* Now that we know all of the positions are settled we'll fill in - any dirty glyphs */ - _cogl_pango_glyph_cache_set_dirty_glyphs (renderer->glyph_cache); -} - -static void -cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer, - PangoRenderPart part) -{ - PangoColor *pango_color = pango_renderer_get_color (renderer, part); - uint16_t alpha = pango_renderer_get_alpha (renderer, part); - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - - if (pango_color) - { - CoglColor color; - - cogl_color_init_from_4f (&color, - pango_color->red / 65535.0f, - pango_color->green / 65535.0f, - pango_color->blue / 65535.0f, - alpha ? alpha / 65535.0f : 1.0f); - - _cogl_pango_display_list_set_color_override (priv->display_list, &color); - } - else - _cogl_pango_display_list_remove_color_override (priv->display_list); -} - -static void -cogl_pango_renderer_draw_box (PangoRenderer *renderer, - int x, - int y, - int width, - int height) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - - g_return_if_fail (priv->display_list != NULL); - - _cogl_pango_display_list_add_rectangle (priv->display_list, - x, - y - height, - x + width, - y); -} - -static void -cogl_pango_renderer_get_device_units (PangoRenderer *renderer, - int xin, - int yin, - float *xout, - float *yout) -{ - const PangoMatrix *matrix; - - if ((matrix = pango_renderer_get_matrix (renderer))) - { - /* Convert user-space coords to device coords */ - *xout = (float) ((xin * matrix->xx + yin * matrix->xy) / - PANGO_SCALE + matrix->x0); - *yout = (float) ((yin * matrix->yy + xin * matrix->yx) / - PANGO_SCALE + matrix->y0); - } - else - { - *xout = PANGO_PIXELS (xin); - *yout = PANGO_PIXELS (yin); - } -} - -static void -cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer, - PangoRenderPart part, - int x, - int y, - int width, - int height) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - float x1, x2, y1, y2; - - g_return_if_fail (priv->display_list != NULL); - - cogl_pango_renderer_set_color_for_part (renderer, part); - - cogl_pango_renderer_get_device_units (renderer, - x, y, - &x1, &y1); - cogl_pango_renderer_get_device_units (renderer, - x + width, y + height, - &x2, &y2); - - _cogl_pango_display_list_add_rectangle (priv->display_list, - x1, y1, x2, y2); -} - -static void -cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer, - PangoRenderPart part, - double y1, - double x11, - double x21, - double y2, - double x12, - double x22) -{ - CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - - g_return_if_fail (priv->display_list != NULL); - - cogl_pango_renderer_set_color_for_part (renderer, part); - - _cogl_pango_display_list_add_trapezoid (priv->display_list, - (float) y1, - (float) x11, - (float) x21, - (float) y2, - (float) x12, - (float) x22); -} - -static void -cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, - PangoFont *font, - PangoGlyphString *glyphs, - int xi, - int yi) -{ - CoglPangoRenderer *priv = (CoglPangoRenderer *) renderer; - CoglPangoGlyphCacheValue *cache_value; - int i; - - for (i = 0; i < glyphs->num_glyphs; i++) - { - PangoGlyphInfo *gi = glyphs->glyphs + i; - float x, y; - - cogl_pango_renderer_set_color_for_part (renderer, - PANGO_RENDER_PART_FOREGROUND); - cogl_pango_renderer_get_device_units (renderer, - xi + gi->geometry.x_offset, - yi + gi->geometry.y_offset, - &x, &y); - - if ((gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)) - { - if (font == NULL) - { - cogl_pango_renderer_draw_box (renderer, - (int) x, - (int) y, - PANGO_UNKNOWN_GLYPH_WIDTH, - PANGO_UNKNOWN_GLYPH_HEIGHT); - } - else - { - PangoRectangle ink_rect; - - pango_font_get_glyph_extents (font, gi->glyph, &ink_rect, NULL); - pango_extents_to_pixels (&ink_rect, NULL); - - cogl_pango_renderer_draw_box (renderer, - (int) (x + ink_rect.x), - (int) (y + ink_rect.y + ink_rect.height), - ink_rect.width, - ink_rect.height); - } - } - else - { - /* Get the texture containing the glyph */ - cache_value = - cogl_pango_renderer_get_cached_glyph (renderer, - FALSE, - font, - gi->glyph); - - /* clutter_ensure_glyph_cache_for_layout should always be - called before rendering a layout so we should never have - a dirty glyph here */ - g_assert (cache_value == NULL || !cache_value->dirty); - - if (cache_value == NULL) - { - cogl_pango_renderer_draw_box (renderer, - (int) x, - (int) y, - PANGO_UNKNOWN_GLYPH_WIDTH, - PANGO_UNKNOWN_GLYPH_HEIGHT); - } - else if (cache_value->texture) - { - x += (float)(cache_value->draw_x); - y += (float)(cache_value->draw_y); - - /* Do not override color if the glyph/font provide its own */ - if (cache_value->has_color) - { - CoglColor color; - uint16_t alpha; - - alpha = pango_renderer_get_alpha (renderer, - PANGO_RENDER_PART_FOREGROUND); - cogl_color_init_from_4f (&color, 1.0f, 1.0f, 1.0f, - alpha ? (alpha >> 8) / 255.0f : 1.0f); - _cogl_pango_display_list_set_color_override (priv->display_list, &color); - } - - cogl_pango_renderer_draw_glyph (priv, cache_value, x, y); - } - } - - xi += gi->geometry.width; - } -} - -static void -cogl_pango_renderer_class_init (CoglPangoRendererClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); - GParamSpec *pspec; - - object_class->set_property = cogl_pango_renderer_set_property; - object_class->constructed = _cogl_pango_renderer_constructed; - object_class->dispose = cogl_pango_renderer_dispose; - object_class->finalize = cogl_pango_renderer_finalize; - - pspec = g_param_spec_object ("context", NULL, NULL, - COGL_TYPE_CONTEXT, - G_PARAM_WRITABLE | - G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_property (object_class, PROP_COGL_CONTEXT, pspec); - - renderer_class->draw_glyphs = cogl_pango_renderer_draw_glyphs; - renderer_class->draw_rectangle = cogl_pango_renderer_draw_rectangle; - renderer_class->draw_trapezoid = cogl_pango_renderer_draw_trapezoid; -}