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-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),

View File

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

View File

@ -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"

View File

@ -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',

View File

@ -31,39 +31,36 @@
#include <glib.h>
#include <string.h>
#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);

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 "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,

View File

@ -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

View File

@ -35,13 +35,11 @@
#include <glib.h>
#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);

View File

@ -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

View File

@ -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:

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;
}