clutter/pango: Rename types post merge

The rename didnt happen as part of the merge as various bits were
removed the commits after, reducing the amount of required changes

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4004>
This commit is contained in:
Bilal Elmoussaoui 2024-09-04 22:11:12 +02:00 committed by Marge Bot
parent f60e9e5e0d
commit 463c36880e
14 changed files with 967 additions and 966 deletions

View File

@ -31,7 +31,7 @@
#include "clutter/clutter-private.h" #include "clutter/clutter-private.h"
#include "clutter/clutter-paint-node-private.h" #include "clutter/clutter-paint-node-private.h"
#include "clutter/clutter-settings-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_show_fps = FALSE;
static gboolean clutter_enable_accessibility = TRUE; static gboolean clutter_enable_accessibility = TRUE;
@ -321,7 +321,7 @@ clutter_context_get_pango_fontmap (ClutterContext *context)
backend = clutter_context_get_backend (context); backend = clutter_context_get_backend (context);
cogl_context = clutter_backend_get_cogl_context (backend); cogl_context = clutter_backend_get_cogl_context (backend);
font_map = pango_cairo_font_map_new (); 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); resolution = clutter_backend_get_resolution (context->backend);
pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map),

View File

@ -30,7 +30,7 @@
#include <pango/pango.h> #include <pango/pango.h>
#include "cogl/cogl.h" #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-actor-private.h"
#include "clutter/clutter-blur-private.h" #include "clutter/clutter-blur-private.h"
#include "clutter/clutter-debug.h" #include "clutter/clutter-debug.h"

View File

@ -46,7 +46,7 @@
#include "clutter/clutter-text.h" #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-text-accessible-private.h"
#include "clutter/clutter-actor-private.h" #include "clutter/clutter-actor-private.h"
#include "clutter/clutter-animatable.h" #include "clutter/clutter-animatable.h"

View File

@ -84,10 +84,10 @@ clutter_headers = [
] ]
clutter_sources = [ clutter_sources = [
'pango/cogl-pango-display-list.c', 'pango/clutter-pango-display-list.c',
'pango/cogl-pango-glyph-cache.c', 'pango/clutter-pango-glyph-cache.c',
'pango/cogl-pango-pipeline-cache.c', 'pango/clutter-pango-pipeline-cache.c',
'pango/cogl-pango-render.c', 'pango/clutter-pango-render.c',
'clutter-accessibility.c', 'clutter-accessibility.c',
'clutter-action.c', 'clutter-action.c',
'clutter-actor-box.c', 'clutter-actor-box.c',
@ -181,10 +181,10 @@ clutter_sources = [
] ]
clutter_private_headers = [ clutter_private_headers = [
'pango/cogl-pango-display-list.h', 'pango/clutter-pango-display-list.h',
'pango/cogl-pango-glyph-cache.h', 'pango/clutter-pango-glyph-cache.h',
'pango/cogl-pango-pipeline-cache.h', 'pango/clutter-pango-pipeline-cache.h',
'pango/cogl-pango-private.h', 'pango/clutter-pango-private.h',
'clutter-accessibility-private.h', 'clutter-accessibility-private.h',
'clutter-actor-meta-private.h', 'clutter-actor-meta-private.h',
'clutter-actor-private.h', 'clutter-actor-private.h',

View File

@ -31,39 +31,36 @@
#include <glib.h> #include <glib.h>
#include <string.h> #include <string.h>
#include "clutter/pango/cogl-pango-display-list.h" #include "clutter/pango/clutter-pango-display-list.h"
#include "clutter/pango/cogl-pango-pipeline-cache.h" #include "clutter/pango/clutter-pango-pipeline-cache.h"
#include "cogl/cogl.h" #include "cogl/cogl.h"
typedef enum typedef enum
{ {
COGL_PANGO_DISPLAY_LIST_TEXTURE, PANGO_DISPLAY_LIST_TEXTURE,
COGL_PANGO_DISPLAY_LIST_RECTANGLE, PANGO_DISPLAY_LIST_RECTANGLE,
COGL_PANGO_DISPLAY_LIST_TRAPEZOID PANGO_DISPLAY_LIST_TRAPEZOID
} CoglPangoDisplayListNodeType; } PangoDisplayListNodeType;
typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; struct _ClutterPangoDisplayList
typedef struct _CoglPangoDisplayListRectangle CoglPangoDisplayListRectangle;
struct _CoglPangoDisplayList
{ {
gboolean color_override; gboolean color_override;
CoglColor color; CoglColor color;
GSList *nodes; GSList *nodes;
GSList *last_node; GSList *last_node;
CoglPangoPipelineCache *pipeline_cache; ClutterPangoPipelineCache *pipeline_cache;
}; };
/* This matches the format expected by cogl_rectangles_with_texture_coords */ /* 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 x_1, y_1, x_2, y_2;
float s_1, t_1, s_2, t_2; float s_1, t_1, s_2, t_2;
}; } PangoDisplayListRectangle;
struct _CoglPangoDisplayListNode typedef struct _PangoDisplayListNode
{ {
CoglPangoDisplayListNodeType type; PangoDisplayListNodeType type;
gboolean color_override; gboolean color_override;
CoglColor color; CoglColor color;
@ -95,12 +92,12 @@ struct _CoglPangoDisplayListNode
CoglPrimitive *primitive; CoglPrimitive *primitive;
} trapezoid; } trapezoid;
} d; } d;
}; } PangoDisplayListNode;
CoglPangoDisplayList * ClutterPangoDisplayList *
_cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache) 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; dl->pipeline_cache = pipeline_cache;
@ -108,8 +105,8 @@ _cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache)
} }
static void static void
_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl, clutter_pango_display_list_append_node (ClutterPangoDisplayList *dl,
CoglPangoDisplayListNode *node) PangoDisplayListNode *node)
{ {
if (dl->last_node) if (dl->last_node)
dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node); dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
@ -118,7 +115,7 @@ _cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
} }
void void
_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl, clutter_pango_display_list_set_color_override (ClutterPangoDisplayList *dl,
const CoglColor *color) const CoglColor *color)
{ {
dl->color_override = TRUE; dl->color_override = TRUE;
@ -126,26 +123,30 @@ _cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
} }
void void
_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl) clutter_pango_display_list_remove_color_override (ClutterPangoDisplayList *dl)
{ {
dl->color_override = FALSE; dl->color_override = FALSE;
} }
void void
_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, clutter_pango_display_list_add_texture (ClutterPangoDisplayList *dl,
CoglTexture *texture, CoglTexture *texture,
float x_1, float y_1, float x_1,
float x_2, float y_2, float y_1,
float tx_1, float ty_1, float x_2,
float tx_2, float ty_2) float y_2,
float tx_1,
float ty_1,
float tx_2,
float ty_2)
{ {
CoglPangoDisplayListNode *node; PangoDisplayListNode *node;
CoglPangoDisplayListRectangle *rectangle; PangoDisplayListRectangle *rectangle;
/* Add to the last node if it is a texture node with the same /* Add to the last node if it is a texture node with the same
target texture */ target texture */
if (dl->last_node 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 && node->d.texture.texture == texture
&& (dl->color_override && (dl->color_override
? (node->color_override && cogl_color_equal (&dl->color, &node->color)) ? (node->color_override && cogl_color_equal (&dl->color, &node->color))
@ -157,24 +158,24 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
else else
{ {
/* Otherwise create a new node */ /* 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_override = dl->color_override;
node->color = dl->color; node->color = dl->color;
node->pipeline = NULL; node->pipeline = NULL;
node->d.texture.texture = g_object_ref (texture); node->d.texture.texture = g_object_ref (texture);
node->d.texture.rectangles node->d.texture.rectangles
= g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListRectangle)); = g_array_new (FALSE, FALSE, sizeof (PangoDisplayListRectangle));
node->d.texture.primitive = NULL; 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, g_array_set_size (node->d.texture.rectangles,
node->d.texture.rectangles->len + 1); node->d.texture.rectangles->len + 1);
rectangle = &g_array_index (node->d.texture.rectangles, rectangle = &g_array_index (node->d.texture.rectangles,
CoglPangoDisplayListRectangle, PangoDisplayListRectangle,
node->d.texture.rectangles->len - 1); node->d.texture.rectangles->len - 1);
rectangle->x_1 = x_1; rectangle->x_1 = x_1;
rectangle->y_1 = y_1; rectangle->y_1 = y_1;
@ -187,13 +188,15 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
} }
void void
_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, clutter_pango_display_list_add_rectangle (ClutterPangoDisplayList *dl,
float x_1, float y_1, float x_1,
float x_2, float y_2) 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_override = dl->color_override;
node->color = dl->color; node->color = dl->color;
node->d.rectangle.x_1 = x_1; node->d.rectangle.x_1 = x_1;
@ -202,11 +205,11 @@ _cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
node->d.rectangle.y_2 = y_2; node->d.rectangle.y_2 = y_2;
node->pipeline = NULL; node->pipeline = NULL;
_cogl_pango_display_list_append_node (dl, node); clutter_pango_display_list_append_node (dl, node);
} }
void void
_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, clutter_pango_display_list_add_trapezoid (ClutterPangoDisplayList *dl,
float y_1, float y_1,
float x_11, float x_11,
float x_21, float x_21,
@ -215,7 +218,7 @@ _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
float x_22) float x_22)
{ {
CoglContext *ctx = dl->pipeline_cache->ctx; CoglContext *ctx = dl->pipeline_cache->ctx;
CoglPangoDisplayListNode *node = g_new0 (CoglPangoDisplayListNode, 1); PangoDisplayListNode *node = g_new0 (PangoDisplayListNode, 1);
CoglVertexP2 vertices[4] = { CoglVertexP2 vertices[4] = {
{ x_11, y_1 }, { x_11, y_1 },
{ x_12, y_2 }, { x_12, y_2 },
@ -223,7 +226,7 @@ _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
{ x_21, y_1 } { 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_override = dl->color_override;
node->color = dl->color; node->color = dl->color;
node->pipeline = NULL; node->pipeline = NULL;
@ -234,13 +237,13 @@ _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
4, 4,
vertices); vertices);
_cogl_pango_display_list_append_node (dl, node); clutter_pango_display_list_append_node (dl, node);
} }
static void static void
emit_rectangles_through_journal (CoglFramebuffer *fb, emit_rectangles_through_journal (CoglFramebuffer *fb,
CoglPipeline *pipeline, CoglPipeline *pipeline,
CoglPangoDisplayListNode *node) PangoDisplayListNode *node)
{ {
const float *rectangles = (const float *)node->d.texture.rectangles->data; const float *rectangles = (const float *)node->d.texture.rectangles->data;
@ -253,7 +256,7 @@ emit_rectangles_through_journal (CoglFramebuffer *fb,
static void static void
emit_vertex_buffer_geometry (CoglFramebuffer *fb, emit_vertex_buffer_geometry (CoglFramebuffer *fb,
CoglPipeline *pipeline, CoglPipeline *pipeline,
CoglPangoDisplayListNode *node) PangoDisplayListNode *node)
{ {
CoglContext *ctx = cogl_framebuffer_get_context (fb); CoglContext *ctx = cogl_framebuffer_get_context (fb);
@ -297,9 +300,9 @@ emit_vertex_buffer_geometry (CoglFramebuffer *fb,
vertices instead of just two */ vertices instead of just two */
for (i = 0; i < node->d.texture.rectangles->len; i++) for (i = 0; i < node->d.texture.rectangles->len; i++)
{ {
const CoglPangoDisplayListRectangle *rectangle const PangoDisplayListRectangle *rectangle
= &g_array_index (node->d.texture.rectangles, = &g_array_index (node->d.texture.rectangles,
CoglPangoDisplayListRectangle, i); PangoDisplayListRectangle, i);
v->x = rectangle->x_1; v->x = rectangle->x_1;
v->y = rectangle->y_1; v->y = rectangle->y_1;
@ -373,7 +376,7 @@ emit_vertex_buffer_geometry (CoglFramebuffer *fb,
static void static void
_cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb, _cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb,
CoglPipeline *pipeline, CoglPipeline *pipeline,
CoglPangoDisplayListNode *node) PangoDisplayListNode *node)
{ {
/* For small runs of text like icon labels, we can get better performance /* 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 * going through the Cogl journal since text may then be batched together
@ -387,8 +390,8 @@ _cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb,
} }
void void
cogl_pango_display_list_render (CoglFramebuffer *fb, clutter_pango_display_list_render (CoglFramebuffer *fb,
CoglPangoDisplayList *dl, ClutterPangoDisplayList *dl,
ClutterColorState *color_state, ClutterColorState *color_state,
ClutterColorState *target_color_state, ClutterColorState *target_color_state,
const CoglColor *color) const CoglColor *color)
@ -397,19 +400,19 @@ cogl_pango_display_list_render (CoglFramebuffer *fb,
for (l = dl->nodes; l; l = l->next) for (l = dl->nodes; l; l = l->next)
{ {
CoglPangoDisplayListNode *node = l->data; PangoDisplayListNode *node = l->data;
CoglColor draw_color; CoglColor draw_color;
g_autoptr (CoglPipeline) pipeline = NULL; g_autoptr (CoglPipeline) pipeline = NULL;
if (node->pipeline == NULL) if (node->pipeline == NULL)
{ {
if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) if (node->type == PANGO_DISPLAY_LIST_TEXTURE)
node->pipeline = node->pipeline =
_cogl_pango_pipeline_cache_get (dl->pipeline_cache, clutter_pango_pipeline_cache_get (dl->pipeline_cache,
node->d.texture.texture); node->d.texture.texture);
else else
node->pipeline = node->pipeline =
_cogl_pango_pipeline_cache_get (dl->pipeline_cache, clutter_pango_pipeline_cache_get (dl->pipeline_cache,
NULL); NULL);
} }
@ -437,11 +440,11 @@ cogl_pango_display_list_render (CoglFramebuffer *fb,
switch (node->type) switch (node->type)
{ {
case COGL_PANGO_DISPLAY_LIST_TEXTURE: case PANGO_DISPLAY_LIST_TEXTURE:
_cogl_framebuffer_draw_display_list_texture (fb, pipeline, node); _cogl_framebuffer_draw_display_list_texture (fb, pipeline, node);
break; break;
case COGL_PANGO_DISPLAY_LIST_RECTANGLE: case PANGO_DISPLAY_LIST_RECTANGLE:
cogl_framebuffer_draw_rectangle (fb, cogl_framebuffer_draw_rectangle (fb,
pipeline, pipeline,
node->d.rectangle.x_1, node->d.rectangle.x_1,
@ -450,7 +453,7 @@ cogl_pango_display_list_render (CoglFramebuffer *fb,
node->d.rectangle.y_2); node->d.rectangle.y_2);
break; break;
case COGL_PANGO_DISPLAY_LIST_TRAPEZOID: case PANGO_DISPLAY_LIST_TRAPEZOID:
cogl_primitive_draw (node->d.trapezoid.primitive, cogl_primitive_draw (node->d.trapezoid.primitive,
fb, fb,
pipeline); pipeline);
@ -460,15 +463,15 @@ cogl_pango_display_list_render (CoglFramebuffer *fb,
} }
static void 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_array_free (node->d.texture.rectangles, TRUE);
g_clear_object (&node->d.texture.texture); g_clear_object (&node->d.texture.texture);
g_clear_object (&node->d.texture.primitive); 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->d.trapezoid.primitive);
g_clear_object (&node->pipeline); g_clear_object (&node->pipeline);
@ -477,10 +480,10 @@ _cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
} }
void void
_cogl_pango_display_list_free (CoglPangoDisplayList *dl) clutter_pango_display_list_free (ClutterPangoDisplayList *dl)
{ {
g_slist_free_full (dl->nodes, (GDestroyNotify) g_slist_free_full (dl->nodes, (GDestroyNotify)
_cogl_pango_display_list_node_free); clutter_pango_display_list_node_free);
dl->nodes = NULL; dl->nodes = NULL;
dl->last_node = NULL; dl->last_node = NULL;
g_free (dl); g_free (dl);

View File

@ -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 <glib.h>
#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

View File

@ -33,12 +33,10 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include "clutter/clutter-debug.h" #include "clutter/clutter-debug.h"
#include "clutter/pango/cogl-pango-glyph-cache.h" #include "clutter/pango/clutter-pango-glyph-cache.h"
#include "clutter/pango/cogl-pango-private.h" #include "clutter/pango/clutter-pango-private.h"
typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey; struct _ClutterPangoGlyphCache
struct _CoglPangoGlyphCache
{ {
CoglContext *ctx; CoglContext *ctx;
@ -58,36 +56,35 @@ struct _CoglPangoGlyphCache
gboolean using_global_atlas; gboolean using_global_atlas;
/* True if some of the glyphs are dirty. This is used as an /* 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 */ 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; PangoFont *font;
PangoGlyph glyph; PangoGlyph glyph;
}; } PangoGlyphCacheKey;
static void static void
cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value) clutter_pango_glyph_cache_value_free (PangoGlyphCacheValue *value)
{ {
g_clear_object (&value->texture); g_clear_object (&value->texture);
g_free (value); g_free (value);
} }
static void static void
cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key) clutter_pango_glyph_cache_key_free (PangoGlyphCacheKey *key)
{ {
g_clear_object (&key->font); g_clear_object (&key->font);
g_free (key); g_free (key);
} }
static unsigned int 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 PangoGlyphCacheKey *cache_key = (const PangoGlyphCacheKey *) key;
= (const CoglPangoGlyphCacheKey *) key;
/* Generate a number affected by both the font and the glyph /* Generate a number affected by both the font and the glyph
number. We can safely directly compare the pointers because the number. We can safely directly compare the pointers because the
@ -97,12 +94,11 @@ cogl_pango_glyph_cache_hash_func (const void *key)
} }
static gboolean 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 PangoGlyphCacheKey *key_a = (const PangoGlyphCacheKey *) a;
= (const CoglPangoGlyphCacheKey *) a; const PangoGlyphCacheKey *key_b = (const PangoGlyphCacheKey *) b;
const CoglPangoGlyphCacheKey *key_b
= (const CoglPangoGlyphCacheKey *) b;
/* We can safely directly compare the pointers for the fonts because /* 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 the key holds a reference to the font so it is not possible that
@ -111,22 +107,22 @@ cogl_pango_glyph_cache_equal_func (const void *a, const void *b)
&& key_a->glyph == key_b->glyph; && key_a->glyph == key_b->glyph;
} }
CoglPangoGlyphCache * ClutterPangoGlyphCache *
cogl_pango_glyph_cache_new (CoglContext *ctx) 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 /* Note: as a rule we don't take references to a CoglContext
* internally since */ * internally since */
cache->ctx = ctx; cache->ctx = ctx;
cache->hash_table = g_hash_table_new_full cache->hash_table = g_hash_table_new_full
(cogl_pango_glyph_cache_hash_func, (clutter_pango_glyph_cache_hash_func,
cogl_pango_glyph_cache_equal_func, clutter_pango_glyph_cache_equal_func,
(GDestroyNotify) cogl_pango_glyph_cache_key_free, (GDestroyNotify) clutter_pango_glyph_cache_key_free,
(GDestroyNotify) cogl_pango_glyph_cache_value_free); (GDestroyNotify) clutter_pango_glyph_cache_value_free);
cache->atlases = NULL; cache->atlases = NULL;
g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook)); g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook));
@ -139,21 +135,21 @@ cogl_pango_glyph_cache_new (CoglContext *ctx)
} }
static void 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); g_hook_list_invoke (&cache->reorganize_callbacks, FALSE);
} }
void void
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache) clutter_pango_glyph_cache_free (ClutterPangoGlyphCache *cache)
{ {
if (cache->using_global_atlas) if (cache->using_global_atlas)
{ {
cogl_atlas_texture_remove_reorganize_callback ( cogl_atlas_texture_remove_reorganize_callback (
cache->ctx, 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); g_slist_foreach (cache->atlases, (GFunc) g_object_unref, NULL);
@ -169,11 +165,11 @@ cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
} }
static void static void
cogl_pango_glyph_cache_update_position_cb (void *user_data, clutter_pango_glyph_cache_update_position_cb (void *user_data,
CoglTexture *new_texture, CoglTexture *new_texture,
const MtkRectangle *rect) const MtkRectangle *rect)
{ {
CoglPangoGlyphCacheValue *value = user_data; PangoGlyphCacheValue *value = user_data;
float tex_width, tex_height; float tex_width, tex_height;
g_clear_object (&value->texture); g_clear_object (&value->texture);
@ -195,10 +191,10 @@ cogl_pango_glyph_cache_update_position_cb (void *user_data,
} }
static gboolean static gboolean
cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_add_to_global_atlas (ClutterPangoGlyphCache *cache,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
CoglPangoGlyphCacheValue *value) PangoGlyphCacheValue *value)
{ {
CoglTexture *texture; CoglTexture *texture;
GError *ignore_error = NULL; GError *ignore_error = NULL;
@ -228,7 +224,7 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
{ {
cogl_atlas_texture_add_reorganize_callback cogl_atlas_texture_add_reorganize_callback
(cache->ctx, (cache->ctx,
cogl_pango_glyph_cache_reorganize_cb, cache); clutter_pango_glyph_cache_reorganize_cb, cache);
cache->using_global_atlas = TRUE; cache->using_global_atlas = TRUE;
} }
@ -236,11 +232,11 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
} }
static gboolean static gboolean
cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_add_to_local_atlas (ClutterPangoGlyphCache *cache,
CoglContext *context, CoglContext *context,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
CoglPangoGlyphCacheValue *value) PangoGlyphCacheValue *value)
{ {
CoglAtlas *atlas = NULL; CoglAtlas *atlas = NULL;
GSList *l; GSList *l;
@ -263,7 +259,7 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8,
COGL_ATLAS_CLEAR_TEXTURE | COGL_ATLAS_CLEAR_TEXTURE |
COGL_ATLAS_DISABLE_MIGRATION, 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); CLUTTER_NOTE (PANGO, "Created new atlas for glyphs: %p", atlas);
/* If we still can't reserve space then something has gone /* If we still can't reserve space then something has gone
seriously wrong so we'll just give up */ 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 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); cache->atlases = g_slist_prepend (cache->atlases, atlas);
} }
@ -285,15 +281,15 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
return TRUE; return TRUE;
} }
CoglPangoGlyphCacheValue * PangoGlyphCacheValue *
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_lookup (ClutterPangoGlyphCache *cache,
CoglContext *context, CoglContext *context,
gboolean create, gboolean create,
PangoFont *font, PangoFont *font,
PangoGlyph glyph) PangoGlyph glyph)
{ {
CoglPangoGlyphCacheKey lookup_key; PangoGlyphCacheKey lookup_key;
CoglPangoGlyphCacheValue *value; PangoGlyphCacheValue *value;
lookup_key.font = font; lookup_key.font = font;
lookup_key.glyph = glyph; lookup_key.glyph = glyph;
@ -302,10 +298,10 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
if (create && value == NULL) if (create && value == NULL)
{ {
CoglPangoGlyphCacheKey *key; PangoGlyphCacheKey *key;
PangoRectangle ink_rect; PangoRectangle ink_rect;
value = g_new0 (CoglPangoGlyphCacheValue, 1); value = g_new0 (PangoGlyphCacheValue, 1);
value->texture = NULL; value->texture = NULL;
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
@ -323,18 +319,18 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
else else
{ {
/* Try adding the glyph to the global atlas... */ /* Try adding the glyph to the global atlas... */
if (!cogl_pango_glyph_cache_add_to_global_atlas (cache, if (!clutter_pango_glyph_cache_add_to_global_atlas (cache,
font, font,
glyph, glyph,
value) && value) &&
/* If it fails try the local atlas */ /* If it fails try the local atlas */
!cogl_pango_glyph_cache_add_to_local_atlas (cache, !clutter_pango_glyph_cache_add_to_local_atlas (cache,
context, context,
font, font,
glyph, glyph,
value)) value))
{ {
cogl_pango_glyph_cache_value_free (value); clutter_pango_glyph_cache_value_free (value);
return NULL; return NULL;
} }
@ -342,7 +338,7 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
cache->has_dirty_glyphs = TRUE; cache->has_dirty_glyphs = TRUE;
} }
key = g_new0 (CoglPangoGlyphCacheKey, 1); key = g_new0 (PangoGlyphCacheKey, 1);
key->font = g_object_ref (font); key->font = g_object_ref (font);
key->glyph = glyph; key->glyph = glyph;
@ -371,12 +367,12 @@ font_has_color_glyphs (const PangoFont *font)
} }
static void static void
_cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr, clutter_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr,
void *value_ptr, void *value_ptr,
void *user_data) void *user_data)
{ {
CoglPangoGlyphCacheKey *key = key_ptr; PangoGlyphCacheKey *key = key_ptr;
CoglPangoGlyphCacheValue *value = value_ptr; PangoGlyphCacheValue *value = value_ptr;
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_t *cr; cairo_t *cr;
cairo_scaled_font_t *scaled_font; cairo_scaled_font_t *scaled_font;
@ -455,7 +451,7 @@ _cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr,
} }
void 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 /* If we know that there are no dirty glyphs then we can shortcut
out early */ out early */
@ -463,14 +459,14 @@ _cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache)
return; return;
g_hash_table_foreach (cache->hash_table, g_hash_table_foreach (cache->hash_table,
_cogl_pango_glyph_cache_set_dirty_glyphs_cb, clutter_pango_glyph_cache_set_dirty_glyphs_cb,
NULL); NULL);
cache->has_dirty_glyphs = FALSE; cache->has_dirty_glyphs = FALSE;
} }
void void
_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_add_reorganize_callback (ClutterPangoGlyphCache *cache,
GHookFunc func, GHookFunc func,
void *user_data) void *user_data)
{ {
@ -481,7 +477,7 @@ _cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache,
} }
void void
_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_remove_reorganize_callback (ClutterPangoGlyphCache *cache,
GHookFunc func, GHookFunc func,
void *user_data) void *user_data)
{ {

View File

@ -35,10 +35,9 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _CoglPangoGlyphCache CoglPangoGlyphCache; typedef struct _ClutterPangoGlyphCache ClutterPangoGlyphCache;
typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue;
struct _CoglPangoGlyphCacheValue typedef struct
{ {
CoglTexture *texture; CoglTexture *texture;
@ -60,32 +59,32 @@ struct _CoglPangoGlyphCacheValue
guint dirty : 1; guint dirty : 1;
/* Set to TRUE if the glyph has colors (eg. emoji) */ /* Set to TRUE if the glyph has colors (eg. emoji) */
guint has_color : 1; guint has_color : 1;
}; } PangoGlyphCacheValue;
CoglPangoGlyphCache * ClutterPangoGlyphCache *
cogl_pango_glyph_cache_new (CoglContext *ctx); clutter_pango_glyph_cache_new (CoglContext *ctx);
void void
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache); clutter_pango_glyph_cache_free (ClutterPangoGlyphCache *cache);
CoglPangoGlyphCacheValue * PangoGlyphCacheValue *
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_lookup (ClutterPangoGlyphCache *cache,
CoglContext *context, CoglContext *context,
gboolean create, gboolean create,
PangoFont *font, PangoFont *font,
PangoGlyph glyph); PangoGlyph glyph);
void void
_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_add_reorganize_callback (ClutterPangoGlyphCache *cache,
GHookFunc func, GHookFunc func,
void *user_data); void *user_data);
void void
_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, clutter_pango_glyph_cache_remove_reorganize_callback (ClutterPangoGlyphCache *cache,
GHookFunc func, GHookFunc func,
void *user_data); void *user_data);
void void
_cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache); clutter_pango_glyph_cache_set_dirty_glyphs (ClutterPangoGlyphCache *cache);
G_END_DECLS G_END_DECLS

View File

@ -35,13 +35,11 @@
#include <glib.h> #include <glib.h>
#include "clutter/pango/cogl-pango-pipeline-cache.h" #include "clutter/pango/clutter-pango-pipeline-cache.h"
typedef struct _CoglPangoPipelineCacheEntry CoglPangoPipelineCacheEntry;
static GQuark pipeline_destroy_notify_key = 0; 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 /* This will take a reference or it can be NULL to represent the
pipeline used to render colors */ pipeline used to render colors */
@ -49,19 +47,19 @@ struct _CoglPangoPipelineCacheEntry
/* This will only take a weak reference */ /* This will only take a weak reference */
CoglPipeline *pipeline; CoglPipeline *pipeline;
}; } PangoPipelineCacheEntry;
static void static void
_cogl_pango_pipeline_cache_key_destroy (void *data) clutter_pango_pipeline_cache_key_destroy (void *data)
{ {
if (data) if (data)
g_object_unref (data); g_object_unref (data);
} }
static void 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); g_clear_object (&cache_entry->texture);
@ -71,10 +69,10 @@ _cogl_pango_pipeline_cache_value_destroy (void *data)
g_free (cache_entry); g_free (cache_entry);
} }
CoglPangoPipelineCache * ClutterPangoPipelineCache *
_cogl_pango_pipeline_cache_new (CoglContext *ctx) 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); cache->ctx = g_object_ref (ctx);
@ -84,8 +82,8 @@ _cogl_pango_pipeline_cache_new (CoglContext *ctx)
cache->hash_table = cache->hash_table =
g_hash_table_new_full (g_direct_hash, g_hash_table_new_full (g_direct_hash,
g_direct_equal, g_direct_equal,
_cogl_pango_pipeline_cache_key_destroy, clutter_pango_pipeline_cache_key_destroy,
_cogl_pango_pipeline_cache_value_destroy); clutter_pango_pipeline_cache_value_destroy);
cache->base_texture_rgba_pipeline = NULL; cache->base_texture_rgba_pipeline = NULL;
cache->base_texture_alpha_pipeline = NULL; cache->base_texture_alpha_pipeline = NULL;
@ -94,7 +92,7 @@ _cogl_pango_pipeline_cache_new (CoglContext *ctx)
} }
static CoglPipeline * static CoglPipeline *
get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache) get_base_texture_rgba_pipeline (ClutterPangoPipelineCache *cache)
{ {
if (cache->base_texture_rgba_pipeline == NULL) if (cache->base_texture_rgba_pipeline == NULL)
{ {
@ -112,7 +110,7 @@ get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache)
} }
static CoglPipeline * static CoglPipeline *
get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache) get_base_texture_alpha_pipeline (ClutterPangoPipelineCache *cache)
{ {
if (cache->base_texture_alpha_pipeline == NULL) if (cache->base_texture_alpha_pipeline == NULL)
{ {
@ -146,7 +144,7 @@ get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache)
typedef struct typedef struct
{ {
CoglPangoPipelineCache *cache; ClutterPangoPipelineCache *cache;
CoglTexture *texture; CoglTexture *texture;
} PipelineDestroyNotifyData; } PipelineDestroyNotifyData;
@ -160,12 +158,12 @@ pipeline_destroy_notify_cb (void *user_data)
} }
CoglPipeline * CoglPipeline *
_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, clutter_pango_pipeline_cache_get (ClutterPangoPipelineCache *cache,
CoglTexture *texture) CoglTexture *texture)
{ {
CoglPangoPipelineCacheEntry *entry; PangoPipelineCacheEntry *entry;
PipelineDestroyNotifyData *destroy_data; 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 */ /* Look for an existing entry */
entry = g_hash_table_lookup (cache->hash_table, texture); 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); return g_object_ref (entry->pipeline);
/* No existing pipeline was found so let's create another */ /* No existing pipeline was found so let's create another */
entry = g_new0 (CoglPangoPipelineCacheEntry, 1); entry = g_new0 (PangoPipelineCacheEntry, 1);
if (texture) if (texture)
{ {
@ -218,7 +216,7 @@ _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache,
} }
void 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_rgba_pipeline);
g_clear_object (&cache->base_texture_alpha_pipeline); g_clear_object (&cache->base_texture_alpha_pipeline);

View File

@ -39,7 +39,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _CoglPangoPipelineCache typedef struct
{ {
CoglContext *ctx; CoglContext *ctx;
@ -47,20 +47,20 @@ typedef struct _CoglPangoPipelineCache
CoglPipeline *base_texture_alpha_pipeline; CoglPipeline *base_texture_alpha_pipeline;
CoglPipeline *base_texture_rgba_pipeline; CoglPipeline *base_texture_rgba_pipeline;
} CoglPangoPipelineCache; } ClutterPangoPipelineCache;
CoglPangoPipelineCache * ClutterPangoPipelineCache *
_cogl_pango_pipeline_cache_new (CoglContext *ctx); clutter_pango_pipeline_cache_new (CoglContext *ctx);
/* Returns a pipeline that can be used to render glyphs in the given /* 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 texture. The pipeline has a new reference so it is up to the caller
to unref it */ to unref it */
CoglPipeline * CoglPipeline *
_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, clutter_pango_pipeline_cache_get (ClutterPangoPipelineCache *cache,
CoglTexture *texture); CoglTexture *texture);
void void
_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache); clutter_pango_pipeline_cache_free (ClutterPangoPipelineCache *cache);
G_END_DECLS G_END_DECLS

View File

@ -43,7 +43,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
PangoRenderer * PangoRenderer *
_cogl_pango_renderer_new (CoglContext *context); clutter_pango_renderer_new (CoglContext *context);
/** /**
* clutter_ensure_glyph_cache_for_layout: * clutter_ensure_glyph_cache_for_layout:

View File

@ -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 <neil@linux.intel.com>
* Robert Bragg <robert@linux.intel.com>
* Matthew Allum <mallum@openedhand.com>
*/
#include "config.h"
#include <pango/pango-fontmap.h>
#include <pango/pangocairo.h>
#include <pango/pango-renderer.h>
#include <cairo.h>
#include <cairo-ft.h>
#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;
}

View File

@ -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 <glib.h>
#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

View File

@ -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 <neil@linux.intel.com>
* Robert Bragg <robert@linux.intel.com>
* Matthew Allum <mallum@openedhand.com>
*/
#include "config.h"
#include <pango/pango-fontmap.h>
#include <pango/pangocairo.h>
#include <pango/pango-renderer.h>
#include <cairo.h>
#include <cairo-ft.h>
#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;
}