mirror of
https://github.com/brl/mutter.git
synced 2025-03-03 19:58:10 +00:00
[cogl] move clutter/pango to clutter/cogl/pango
As part of the re-organisation of Cogl; move clutter/pango to be part of the cogl sub-project.
This commit is contained in:
parent
0bce7eac53
commit
17e899a49d
@ -1 +1 @@
|
|||||||
SUBDIRS = cogl
|
SUBDIRS = cogl pango
|
||||||
|
33
pango/Makefile.am
Normal file
33
pango/Makefile.am
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
include $(top_srcdir)/build/autotools/Makefile.am.silent
|
||||||
|
|
||||||
|
source_c = \
|
||||||
|
cogl-pango-display-list.c \
|
||||||
|
cogl-pango-fontmap.c \
|
||||||
|
cogl-pango-render.c \
|
||||||
|
cogl-pango-glyph-cache.c
|
||||||
|
|
||||||
|
source_h = cogl-pango.h
|
||||||
|
|
||||||
|
source_h_priv = \
|
||||||
|
cogl-pango-display-list.h \
|
||||||
|
cogl-pango-private.h \
|
||||||
|
cogl-pango-glyph-cache.h
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libcoglpango.la
|
||||||
|
|
||||||
|
libcoglpango_la_SOURCES = $(source_c) $(source_h) $(source_h_priv)
|
||||||
|
libcoglpango_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
|
||||||
|
libcoglpango_la_LIBADD = $(CLUTTER_LIBS)
|
||||||
|
|
||||||
|
INCLUDES = \
|
||||||
|
-DG_DISABLE_SINGLE_INCLUDES \
|
||||||
|
-DCLUTTER_COMPILATION \
|
||||||
|
-DG_LOG_DOMAIN=\"CoglPango\" \
|
||||||
|
-I$(top_srcdir) \
|
||||||
|
-I$(top_srcdir)/clutter \
|
||||||
|
-I$(top_srcdir)/clutter/cogl \
|
||||||
|
-I$(top_builddir)/clutter \
|
||||||
|
-I$(top_builddir)/clutter/cogl
|
||||||
|
|
||||||
|
coglpangoheadersdir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl
|
||||||
|
coglpangoheaders_HEADERS = $(source_h)
|
417
pango/cogl-pango-display-list.c
Normal file
417
pango/cogl-pango-display-list.c
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Neil Roberts <neil@linux.intel.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Intel Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cogl-pango-display-list.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
COGL_PANGO_DISPLAY_LIST_TEXTURE,
|
||||||
|
COGL_PANGO_DISPLAY_LIST_RECTANGLE,
|
||||||
|
COGL_PANGO_DISPLAY_LIST_TRAPEZOID
|
||||||
|
} CoglPangoDisplayListNodeType;
|
||||||
|
|
||||||
|
typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode;
|
||||||
|
typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex;
|
||||||
|
|
||||||
|
struct _CoglPangoDisplayList
|
||||||
|
{
|
||||||
|
gboolean color_override;
|
||||||
|
CoglColor color;
|
||||||
|
GSList *nodes;
|
||||||
|
GSList *last_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _CoglPangoDisplayListNode
|
||||||
|
{
|
||||||
|
CoglPangoDisplayListNodeType type;
|
||||||
|
|
||||||
|
gboolean color_override;
|
||||||
|
CoglColor color;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* The texture to render these coords from */
|
||||||
|
CoglHandle texture;
|
||||||
|
/* Array of vertex data to render out of this texture */
|
||||||
|
GArray *verts;
|
||||||
|
/* A VBO representing those vertices */
|
||||||
|
CoglHandle vertex_buffer;
|
||||||
|
} texture;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float x_1, y_1;
|
||||||
|
float x_2, y_2;
|
||||||
|
} rectangle;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float y_1;
|
||||||
|
float x_11;
|
||||||
|
float x_21;
|
||||||
|
float y_2;
|
||||||
|
float x_12;
|
||||||
|
float x_22;
|
||||||
|
} trapezoid;
|
||||||
|
} d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _CoglPangoDisplayListVertex
|
||||||
|
{
|
||||||
|
float x, y, t_x, t_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
CoglPangoDisplayList *
|
||||||
|
_cogl_pango_display_list_new (void)
|
||||||
|
{
|
||||||
|
return g_slice_new0 (CoglPangoDisplayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
|
||||||
|
CoglPangoDisplayListNode *node)
|
||||||
|
{
|
||||||
|
if (dl->last_node)
|
||||||
|
dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
|
||||||
|
else
|
||||||
|
dl->last_node = dl->nodes = g_slist_prepend (NULL, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
|
||||||
|
const CoglColor *color)
|
||||||
|
{
|
||||||
|
dl->color_override = TRUE;
|
||||||
|
dl->color = *color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl)
|
||||||
|
{
|
||||||
|
dl->color_override = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
|
||||||
|
CoglHandle 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;
|
||||||
|
CoglPangoDisplayListVertex *verts;
|
||||||
|
|
||||||
|
/* 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->d.texture.texture == texture
|
||||||
|
&& (dl->color_override
|
||||||
|
? (node->color_override && cogl_color_equal (&dl->color, &node->color))
|
||||||
|
: !node->color_override))
|
||||||
|
{
|
||||||
|
/* Get rid of the vertex buffer so that it will be recreated */
|
||||||
|
if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
|
||||||
|
node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise create a new node */
|
||||||
|
node = g_slice_new (CoglPangoDisplayListNode);
|
||||||
|
|
||||||
|
node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE;
|
||||||
|
node->color_override = dl->color_override;
|
||||||
|
node->color = dl->color;
|
||||||
|
node->d.texture.texture = cogl_texture_ref (texture);
|
||||||
|
node->d.texture.verts
|
||||||
|
= g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListVertex));
|
||||||
|
node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
_cogl_pango_display_list_append_node (dl, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_array_set_size (node->d.texture.verts,
|
||||||
|
node->d.texture.verts->len + 4);
|
||||||
|
verts = &g_array_index (node->d.texture.verts,
|
||||||
|
CoglPangoDisplayListVertex,
|
||||||
|
node->d.texture.verts->len - 4);
|
||||||
|
|
||||||
|
verts->x = x_1;
|
||||||
|
verts->y = y_1;
|
||||||
|
verts->t_x = tx_1;
|
||||||
|
verts->t_y = ty_1;
|
||||||
|
verts++;
|
||||||
|
verts->x = x_1;
|
||||||
|
verts->y = y_2;
|
||||||
|
verts->t_x = tx_1;
|
||||||
|
verts->t_y = ty_2;
|
||||||
|
verts++;
|
||||||
|
verts->x = x_2;
|
||||||
|
verts->y = y_2;
|
||||||
|
verts->t_x = tx_2;
|
||||||
|
verts->t_y = ty_2;
|
||||||
|
verts++;
|
||||||
|
verts->x = x_2;
|
||||||
|
verts->y = y_1;
|
||||||
|
verts->t_x = tx_2;
|
||||||
|
verts->t_y = ty_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
|
||||||
|
float x_1, float y_1,
|
||||||
|
float x_2, float y_2)
|
||||||
|
{
|
||||||
|
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
|
||||||
|
|
||||||
|
node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE;
|
||||||
|
node->color_override = dl->color_override;
|
||||||
|
node->color = dl->color;
|
||||||
|
node->d.rectangle.x_1 = x_1;
|
||||||
|
node->d.rectangle.y_1 = y_1;
|
||||||
|
node->d.rectangle.x_2 = x_2;
|
||||||
|
node->d.rectangle.y_2 = y_2;
|
||||||
|
|
||||||
|
_cogl_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)
|
||||||
|
{
|
||||||
|
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
|
||||||
|
|
||||||
|
node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID;
|
||||||
|
node->color_override = dl->color_override;
|
||||||
|
node->color = dl->color;
|
||||||
|
node->d.trapezoid.y_1 = y_1;
|
||||||
|
node->d.trapezoid.x_11 = x_11;
|
||||||
|
node->d.trapezoid.x_21 = x_21;
|
||||||
|
node->d.trapezoid.y_2 = y_2;
|
||||||
|
node->d.trapezoid.x_12 = x_12;
|
||||||
|
node->d.trapezoid.x_22 = x_22;
|
||||||
|
|
||||||
|
_cogl_pango_display_list_append_node (dl, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cogl_pango_display_list_render_texture (CoglHandle material,
|
||||||
|
const CoglColor *color,
|
||||||
|
CoglPangoDisplayListNode *node)
|
||||||
|
{
|
||||||
|
CoglColor premult_color = *color;
|
||||||
|
cogl_material_set_layer (material, 0, node->d.texture.texture);
|
||||||
|
cogl_material_set_color (material, &premult_color);
|
||||||
|
cogl_set_source (material);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
* with other geometry. */
|
||||||
|
/* FIXME: 100 is a number I plucked out of thin air; it would be good
|
||||||
|
* to determine this empirically! */
|
||||||
|
if (node->d.texture.verts->len < 100)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < node->d.texture.verts->len; i += 4)
|
||||||
|
{
|
||||||
|
CoglPangoDisplayListVertex *v0 =
|
||||||
|
&g_array_index (node->d.texture.verts,
|
||||||
|
CoglPangoDisplayListVertex, i);
|
||||||
|
CoglPangoDisplayListVertex *v1 =
|
||||||
|
&g_array_index (node->d.texture.verts,
|
||||||
|
CoglPangoDisplayListVertex, i + 2);
|
||||||
|
cogl_rectangle_with_texture_coords (v0->x, v0->y, v1->x, v1->y,
|
||||||
|
v0->t_x, v0->t_y,
|
||||||
|
v1->t_x, v1->t_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It's expensive to go through the Cogl journal for large runs
|
||||||
|
* of text in part because the journal transforms the quads in software
|
||||||
|
* to avoid changing the modelview matrix. So for larger runs of text
|
||||||
|
* we load the vertices into a VBO, and this has the added advantage
|
||||||
|
* that if the text doesn't change from frame to frame the VBO can
|
||||||
|
* be re-used avoiding the repeated cost of validating the data and
|
||||||
|
* mapping it into the GPU... */
|
||||||
|
|
||||||
|
if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len);
|
||||||
|
|
||||||
|
cogl_vertex_buffer_add (vb, "gl_Vertex", 2,
|
||||||
|
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
|
||||||
|
sizeof (CoglPangoDisplayListVertex),
|
||||||
|
&g_array_index (node->d.texture.verts,
|
||||||
|
CoglPangoDisplayListVertex, 0).x);
|
||||||
|
cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2,
|
||||||
|
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
|
||||||
|
sizeof (CoglPangoDisplayListVertex),
|
||||||
|
&g_array_index (node->d.texture.verts,
|
||||||
|
CoglPangoDisplayListVertex,
|
||||||
|
0).t_x);
|
||||||
|
cogl_vertex_buffer_submit (vb);
|
||||||
|
|
||||||
|
node->d.texture.vertex_buffer = vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CLUTTER_COGL_HAS_GL
|
||||||
|
|
||||||
|
cogl_vertex_buffer_draw (node->d.texture.vertex_buffer,
|
||||||
|
GL_QUADS,
|
||||||
|
0, node->d.texture.verts->len);
|
||||||
|
|
||||||
|
#else /* CLUTTER_COGL_HAS_GL */
|
||||||
|
{
|
||||||
|
/* GLES doesn't support GL_QUADS so instead we use a VBO with
|
||||||
|
indexed vertices to generate GL_TRIANGLES from the quads */
|
||||||
|
|
||||||
|
int n_indices = node->d.texture.verts->len / 4 * 6;
|
||||||
|
CoglHandle indices_vbo
|
||||||
|
= cogl_vertex_buffer_indices_get_for_quads (n_indices);
|
||||||
|
|
||||||
|
cogl_vertex_buffer_draw_elements (node->d.texture.vertex_buffer,
|
||||||
|
COGL_VERTICES_MODE_TRIANGLES,
|
||||||
|
indices_vbo,
|
||||||
|
0, node->d.texture.verts->len - 1,
|
||||||
|
0, n_indices);
|
||||||
|
}
|
||||||
|
#endif /* CLUTTER_COGL_HAS_GL */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_render (CoglPangoDisplayList *dl,
|
||||||
|
const CoglColor *color,
|
||||||
|
CoglHandle glyph_material,
|
||||||
|
CoglHandle solid_material)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
for (l = dl->nodes; l; l = l->next)
|
||||||
|
{
|
||||||
|
CoglPangoDisplayListNode *node = l->data;
|
||||||
|
CoglColor draw_color;
|
||||||
|
|
||||||
|
if (node->color_override)
|
||||||
|
/* Use the override color but preserve the alpha from the
|
||||||
|
draw color */
|
||||||
|
cogl_color_set_from_4ub (&draw_color,
|
||||||
|
cogl_color_get_red_byte (&node->color),
|
||||||
|
cogl_color_get_green_byte (&node->color),
|
||||||
|
cogl_color_get_blue_byte (&node->color),
|
||||||
|
cogl_color_get_alpha_byte (color));
|
||||||
|
else
|
||||||
|
draw_color = *color;
|
||||||
|
cogl_color_premultiply (&draw_color);
|
||||||
|
|
||||||
|
switch (node->type)
|
||||||
|
{
|
||||||
|
case COGL_PANGO_DISPLAY_LIST_TEXTURE:
|
||||||
|
_cogl_pango_display_list_render_texture (glyph_material,
|
||||||
|
&draw_color, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COGL_PANGO_DISPLAY_LIST_RECTANGLE:
|
||||||
|
cogl_material_set_color (solid_material, &draw_color);
|
||||||
|
cogl_set_source (solid_material);
|
||||||
|
cogl_rectangle (node->d.rectangle.x_1,
|
||||||
|
node->d.rectangle.y_1,
|
||||||
|
node->d.rectangle.x_2,
|
||||||
|
node->d.rectangle.y_2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
|
||||||
|
{
|
||||||
|
float points[8];
|
||||||
|
|
||||||
|
points[0] = node->d.trapezoid.x_11;
|
||||||
|
points[1] = node->d.trapezoid.y_1;
|
||||||
|
points[2] = node->d.trapezoid.x_12;
|
||||||
|
points[3] = node->d.trapezoid.y_2;
|
||||||
|
points[4] = node->d.trapezoid.x_22;
|
||||||
|
points[5] = node->d.trapezoid.y_2;
|
||||||
|
points[6] = node->d.trapezoid.x_21;
|
||||||
|
points[7] = node->d.trapezoid.y_1;
|
||||||
|
|
||||||
|
cogl_material_set_color (solid_material, &draw_color);
|
||||||
|
cogl_set_source (solid_material);
|
||||||
|
cogl_path_polygon (points, 4);
|
||||||
|
cogl_path_fill ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
|
||||||
|
{
|
||||||
|
if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
|
||||||
|
{
|
||||||
|
g_array_free (node->d.texture.verts, TRUE);
|
||||||
|
if (node->d.texture.texture != COGL_INVALID_HANDLE)
|
||||||
|
cogl_texture_unref (node->d.texture.texture);
|
||||||
|
if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
|
||||||
|
cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slice_free (CoglPangoDisplayListNode, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_clear (CoglPangoDisplayList *dl)
|
||||||
|
{
|
||||||
|
g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL);
|
||||||
|
g_slist_free (dl->nodes);
|
||||||
|
dl->nodes = NULL;
|
||||||
|
dl->last_node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_display_list_free (CoglPangoDisplayList *dl)
|
||||||
|
{
|
||||||
|
_cogl_pango_display_list_clear (dl);
|
||||||
|
g_slice_free (CoglPangoDisplayList, dl);
|
||||||
|
}
|
70
pango/cogl-pango-display-list.h
Normal file
70
pango/cogl-pango-display-list.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Neil Roberts <neil@linux.intel.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Intel Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COGL_PANGO_DISPLAY_LIST_H__
|
||||||
|
#define __COGL_PANGO_DISPLAY_LIST_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _CoglPangoDisplayList CoglPangoDisplayList;
|
||||||
|
|
||||||
|
CoglPangoDisplayList *_cogl_pango_display_list_new (void);
|
||||||
|
|
||||||
|
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,
|
||||||
|
CoglHandle 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 (CoglPangoDisplayList *dl,
|
||||||
|
const CoglColor *color,
|
||||||
|
CoglHandle glyph_material,
|
||||||
|
CoglHandle solid_material);
|
||||||
|
|
||||||
|
void _cogl_pango_display_list_clear (CoglPangoDisplayList *dl);
|
||||||
|
|
||||||
|
void _cogl_pango_display_list_free (CoglPangoDisplayList *dl);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __COGL_PANGO_DISPLAY_LIST_H__ */
|
209
pango/cogl-pango-fontmap.c
Normal file
209
pango/cogl-pango-fontmap.c
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:cogl-pango
|
||||||
|
* @short_description: COGL-based text rendering using Pango
|
||||||
|
*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This is needed to get the Pango headers to export stuff needed to
|
||||||
|
subclass */
|
||||||
|
#ifndef PANGO_ENABLE_BACKEND
|
||||||
|
#define PANGO_ENABLE_BACKEND 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pango/pango-fontmap.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
#include <pango/pango-renderer.h>
|
||||||
|
|
||||||
|
#include "cogl-pango.h"
|
||||||
|
#include "cogl-pango-private.h"
|
||||||
|
|
||||||
|
static GQuark cogl_pango_font_map_get_renderer_key (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_new:
|
||||||
|
*
|
||||||
|
* Creates a new font map.
|
||||||
|
*
|
||||||
|
* Return value: the newly created #PangoFontMap
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
PangoFontMap *
|
||||||
|
cogl_pango_font_map_new (void)
|
||||||
|
{
|
||||||
|
return pango_cairo_font_map_new ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_create_context:
|
||||||
|
* @fm: a #CoglPangoFontMap
|
||||||
|
*
|
||||||
|
* Creates a new #PangoContext from the passed font map.
|
||||||
|
*
|
||||||
|
* Return value: the newly created #PangoContext
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
PangoContext *
|
||||||
|
cogl_pango_font_map_create_context (CoglPangoFontMap *fm)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (COGL_PANGO_IS_FONT_MAP (fm), NULL);
|
||||||
|
|
||||||
|
/* We can just directly use the pango context from the Cairo font
|
||||||
|
map */
|
||||||
|
return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_get_renderer:
|
||||||
|
* @fm: a #CoglPangoFontMap
|
||||||
|
*
|
||||||
|
* Retrieves the #CoglPangoRenderer for the passed font map.
|
||||||
|
*
|
||||||
|
* Return value: a #PangoRenderer
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
PangoRenderer *
|
||||||
|
cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm)
|
||||||
|
{
|
||||||
|
PangoRenderer *renderer;
|
||||||
|
|
||||||
|
g_return_val_if_fail (COGL_PANGO_IS_FONT_MAP (fm), NULL);
|
||||||
|
|
||||||
|
/* We want to keep a cached pointer to the renderer from the font
|
||||||
|
map instance but as we don't have a proper subclass we have to
|
||||||
|
store it in the object data instead */
|
||||||
|
|
||||||
|
renderer = g_object_get_qdata (G_OBJECT (fm),
|
||||||
|
cogl_pango_font_map_get_renderer_key ());
|
||||||
|
|
||||||
|
if (G_UNLIKELY (renderer == NULL))
|
||||||
|
{
|
||||||
|
renderer = g_object_new (COGL_PANGO_TYPE_RENDERER, NULL);
|
||||||
|
g_object_set_qdata_full (G_OBJECT (fm),
|
||||||
|
cogl_pango_font_map_get_renderer_key (),
|
||||||
|
renderer,
|
||||||
|
g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_set_resolution:
|
||||||
|
* @font_map: a #CoglPangoFontMap
|
||||||
|
* @dpi: DPI to set
|
||||||
|
*
|
||||||
|
* Sets the resolution to be used by @font_map at @dpi.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
|
||||||
|
double dpi)
|
||||||
|
{
|
||||||
|
g_return_if_fail (COGL_PANGO_IS_FONT_MAP (font_map));
|
||||||
|
|
||||||
|
pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), dpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_clear_glyph_cache:
|
||||||
|
* @fm: a #CoglPangoFontMap
|
||||||
|
*
|
||||||
|
* Clears the glyph cache for @fm.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *fm)
|
||||||
|
{
|
||||||
|
PangoRenderer *renderer;
|
||||||
|
|
||||||
|
renderer = cogl_pango_font_map_get_renderer (fm);
|
||||||
|
|
||||||
|
_cogl_pango_renderer_clear_glyph_cache (COGL_PANGO_RENDERER (renderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_set_use_mipmapping:
|
||||||
|
* @fm: a #CoglPangoFontMap
|
||||||
|
* @value: %TRUE to enable the use of mipmapping
|
||||||
|
*
|
||||||
|
* Sets whether the renderer for the passed font map should use
|
||||||
|
* mipmapping when rendering a #PangoLayout.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *fm,
|
||||||
|
gboolean value)
|
||||||
|
{
|
||||||
|
CoglPangoRenderer *renderer;
|
||||||
|
|
||||||
|
renderer = COGL_PANGO_RENDERER (cogl_pango_font_map_get_renderer (fm));
|
||||||
|
|
||||||
|
_cogl_pango_renderer_set_use_mipmapping (renderer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_font_map_get_use_mipmapping:
|
||||||
|
* @fm: a #CoglPangoFontMap
|
||||||
|
*
|
||||||
|
* Retrieves whether the #CoglPangoRenderer used by @fm will
|
||||||
|
* use mipmapping when rendering the glyphs.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if mipmapping is used, %FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *fm)
|
||||||
|
{
|
||||||
|
CoglPangoRenderer *renderer;
|
||||||
|
|
||||||
|
renderer = COGL_PANGO_RENDERER (cogl_pango_font_map_get_renderer (fm));
|
||||||
|
|
||||||
|
return _cogl_pango_renderer_get_use_mipmapping (renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GQuark
|
||||||
|
cogl_pango_font_map_get_renderer_key (void)
|
||||||
|
{
|
||||||
|
static GQuark renderer_key = 0;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (renderer_key == 0))
|
||||||
|
renderer_key = g_quark_from_static_string ("CoglPangoFontMap");
|
||||||
|
|
||||||
|
return renderer_key;
|
||||||
|
}
|
352
pango/cogl-pango-glyph-cache.c
Normal file
352
pango/cogl-pango-glyph-cache.c
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "cogl-pango-glyph-cache.h"
|
||||||
|
#include "cogl-pango-private.h"
|
||||||
|
|
||||||
|
/* Minimum width/height for each texture */
|
||||||
|
#define MIN_TEXTURE_SIZE 256
|
||||||
|
/* All glyph with heights within this margin from each other can be
|
||||||
|
put in the same band */
|
||||||
|
#define BAND_HEIGHT_ROUND 4
|
||||||
|
|
||||||
|
typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey;
|
||||||
|
typedef struct _CoglPangoGlyphCacheTexture CoglPangoGlyphCacheTexture;
|
||||||
|
typedef struct _CoglPangoGlyphCacheBand CoglPangoGlyphCacheBand;
|
||||||
|
|
||||||
|
struct _CoglPangoGlyphCache
|
||||||
|
{
|
||||||
|
/* Hash table to quickly check whether a particular glyph in a
|
||||||
|
particular font is already cached */
|
||||||
|
GHashTable *hash_table;
|
||||||
|
|
||||||
|
/* List of textures */
|
||||||
|
CoglPangoGlyphCacheTexture *textures;
|
||||||
|
|
||||||
|
/* List of horizontal bands of glyphs */
|
||||||
|
CoglPangoGlyphCacheBand *bands;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _CoglPangoGlyphCacheKey
|
||||||
|
{
|
||||||
|
PangoFont *font;
|
||||||
|
PangoGlyph glyph;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Represents one texture that will be used to store glyphs. The
|
||||||
|
texture is divided into horizontal bands which all contain glyphs
|
||||||
|
of approximatly the same height */
|
||||||
|
struct _CoglPangoGlyphCacheTexture
|
||||||
|
{
|
||||||
|
/* The width and height of the texture which should always be a
|
||||||
|
power of two. This can vary so that glyphs larger than
|
||||||
|
MIN_TEXTURE_SIZE can use a bigger texture */
|
||||||
|
int texture_size;
|
||||||
|
|
||||||
|
/* The remaining vertical space not taken up by any bands */
|
||||||
|
int space_remaining;
|
||||||
|
|
||||||
|
/* The actual texture */
|
||||||
|
CoglHandle texture;
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheTexture *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Represents one horizontal band of a texture. Each band contains
|
||||||
|
glyphs of a similar height */
|
||||||
|
struct _CoglPangoGlyphCacheBand
|
||||||
|
{
|
||||||
|
/* The y position of the top of the band */
|
||||||
|
int top;
|
||||||
|
|
||||||
|
/* The height of the band */
|
||||||
|
int height;
|
||||||
|
|
||||||
|
/* The remaining horizontal space not taken up by any glyphs */
|
||||||
|
int space_remaining;
|
||||||
|
|
||||||
|
/* The size of the texture. Needed to calculate texture
|
||||||
|
coordinates */
|
||||||
|
int texture_size;
|
||||||
|
|
||||||
|
/* The texture containing this band */
|
||||||
|
CoglHandle texture;
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheBand *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value)
|
||||||
|
{
|
||||||
|
cogl_handle_unref (value->texture);
|
||||||
|
g_slice_free (CoglPangoGlyphCacheValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key)
|
||||||
|
{
|
||||||
|
g_object_unref (key->font);
|
||||||
|
g_slice_free (CoglPangoGlyphCacheKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
cogl_pango_glyph_cache_hash_func (gconstpointer key)
|
||||||
|
{
|
||||||
|
const CoglPangoGlyphCacheKey *cache_key
|
||||||
|
= (const CoglPangoGlyphCacheKey *) key;
|
||||||
|
|
||||||
|
/* Generate a number affected by both the font and the glyph
|
||||||
|
number. We can safely directly compare the pointers 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 GPOINTER_TO_UINT (cache_key->font) ^ cache_key->glyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
cogl_pango_glyph_cache_equal_func (gconstpointer a,
|
||||||
|
gconstpointer b)
|
||||||
|
{
|
||||||
|
const CoglPangoGlyphCacheKey *key_a
|
||||||
|
= (const CoglPangoGlyphCacheKey *) a;
|
||||||
|
const CoglPangoGlyphCacheKey *key_b
|
||||||
|
= (const CoglPangoGlyphCacheKey *) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_glyph_cache_free_textures (CoglPangoGlyphCacheTexture *node)
|
||||||
|
{
|
||||||
|
CoglPangoGlyphCacheTexture *next;
|
||||||
|
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
next = node->next;
|
||||||
|
cogl_handle_unref (node->texture);
|
||||||
|
g_slice_free (CoglPangoGlyphCacheTexture, node);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_glyph_cache_free_bands (CoglPangoGlyphCacheBand *node)
|
||||||
|
{
|
||||||
|
CoglPangoGlyphCacheBand *next;
|
||||||
|
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
next = node->next;
|
||||||
|
cogl_handle_unref (node->texture);
|
||||||
|
g_slice_free (CoglPangoGlyphCacheBand, node);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglPangoGlyphCache *
|
||||||
|
cogl_pango_glyph_cache_new (void)
|
||||||
|
{
|
||||||
|
CoglPangoGlyphCache *cache;
|
||||||
|
|
||||||
|
cache = g_malloc (sizeof (CoglPangoGlyphCache));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
cache->textures = NULL;
|
||||||
|
cache->bands = NULL;
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache)
|
||||||
|
{
|
||||||
|
cogl_pango_glyph_cache_free_textures (cache->textures);
|
||||||
|
cache->textures = NULL;
|
||||||
|
cogl_pango_glyph_cache_free_bands (cache->bands);
|
||||||
|
cache->bands = NULL;
|
||||||
|
|
||||||
|
g_hash_table_remove_all (cache->hash_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
|
||||||
|
{
|
||||||
|
cogl_pango_glyph_cache_clear (cache);
|
||||||
|
|
||||||
|
g_hash_table_unref (cache->hash_table);
|
||||||
|
|
||||||
|
g_free (cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheValue *
|
||||||
|
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyph glyph)
|
||||||
|
{
|
||||||
|
CoglPangoGlyphCacheKey key;
|
||||||
|
|
||||||
|
key.font = font;
|
||||||
|
key.glyph = glyph;
|
||||||
|
|
||||||
|
return (CoglPangoGlyphCacheValue *)
|
||||||
|
g_hash_table_lookup (cache->hash_table, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheValue *
|
||||||
|
cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyph glyph,
|
||||||
|
gconstpointer pixels,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int stride,
|
||||||
|
int draw_x,
|
||||||
|
int draw_y)
|
||||||
|
{
|
||||||
|
int band_height;
|
||||||
|
CoglPangoGlyphCacheBand *band;
|
||||||
|
CoglPangoGlyphCacheKey *key;
|
||||||
|
CoglPangoGlyphCacheValue *value;
|
||||||
|
|
||||||
|
/* Reserve an extra pixel gap around the glyph so that it can pull
|
||||||
|
in blank pixels when linear filtering is enabled */
|
||||||
|
width++;
|
||||||
|
height++;
|
||||||
|
|
||||||
|
/* Round the height up to the nearest multiple of
|
||||||
|
BAND_HEIGHT_ROUND */
|
||||||
|
band_height = (height + BAND_HEIGHT_ROUND - 1) & ~(BAND_HEIGHT_ROUND - 1);
|
||||||
|
|
||||||
|
/* Look for a band with the same height and enough width available */
|
||||||
|
for (band = cache->bands;
|
||||||
|
band && (band->height != band_height || band->space_remaining < width);
|
||||||
|
band = band->next);
|
||||||
|
if (band == NULL)
|
||||||
|
{
|
||||||
|
CoglPangoGlyphCacheTexture *texture;
|
||||||
|
|
||||||
|
/* Look for a texture with enough vertical space left for a band
|
||||||
|
with this height */
|
||||||
|
for (texture = cache->textures;
|
||||||
|
texture && (texture->space_remaining < band_height
|
||||||
|
|| texture->texture_size < width);
|
||||||
|
texture = texture->next);
|
||||||
|
if (texture == NULL)
|
||||||
|
{
|
||||||
|
guchar *clear_data;
|
||||||
|
|
||||||
|
/* Allocate a new texture that is the nearest power of two
|
||||||
|
greater than the band height or the minimum size,
|
||||||
|
whichever is lower */
|
||||||
|
texture = g_slice_new (CoglPangoGlyphCacheTexture);
|
||||||
|
|
||||||
|
texture->texture_size = MIN_TEXTURE_SIZE;
|
||||||
|
while (texture->texture_size < band_height ||
|
||||||
|
texture->texture_size < width)
|
||||||
|
{
|
||||||
|
texture->texture_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate an empty buffer to clear the texture */
|
||||||
|
clear_data =
|
||||||
|
g_malloc0 (texture->texture_size * texture->texture_size);
|
||||||
|
|
||||||
|
texture->texture =
|
||||||
|
cogl_texture_new_from_data (texture->texture_size,
|
||||||
|
texture->texture_size,
|
||||||
|
COGL_TEXTURE_NONE,
|
||||||
|
COGL_PIXEL_FORMAT_A_8,
|
||||||
|
COGL_PIXEL_FORMAT_A_8,
|
||||||
|
texture->texture_size,
|
||||||
|
clear_data);
|
||||||
|
|
||||||
|
g_free (clear_data);
|
||||||
|
|
||||||
|
texture->space_remaining = texture->texture_size;
|
||||||
|
texture->next = cache->textures;
|
||||||
|
cache->textures = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
band = g_slice_new (CoglPangoGlyphCacheBand);
|
||||||
|
band->top = texture->texture_size - texture->space_remaining;
|
||||||
|
band->height = band_height;
|
||||||
|
band->space_remaining = texture->texture_size;
|
||||||
|
band->texture = cogl_handle_ref (texture->texture);
|
||||||
|
band->texture_size = texture->texture_size;
|
||||||
|
band->next = cache->bands;
|
||||||
|
cache->bands = band;
|
||||||
|
texture->space_remaining -= band_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
band->space_remaining -= width;
|
||||||
|
|
||||||
|
width--;
|
||||||
|
height--;
|
||||||
|
|
||||||
|
cogl_texture_set_region (band->texture,
|
||||||
|
0, 0,
|
||||||
|
band->space_remaining,
|
||||||
|
band->top,
|
||||||
|
width, height,
|
||||||
|
width, height,
|
||||||
|
COGL_PIXEL_FORMAT_A_8,
|
||||||
|
stride,
|
||||||
|
pixels);
|
||||||
|
|
||||||
|
key = g_slice_new (CoglPangoGlyphCacheKey);
|
||||||
|
key->font = g_object_ref (font);
|
||||||
|
key->glyph = glyph;
|
||||||
|
|
||||||
|
value = g_slice_new (CoglPangoGlyphCacheValue);
|
||||||
|
value->texture = cogl_handle_ref (band->texture);
|
||||||
|
value->tx1 = (float)(band->space_remaining)
|
||||||
|
/ band->texture_size;
|
||||||
|
value->tx2 = (float)(band->space_remaining + width)
|
||||||
|
/ band->texture_size;
|
||||||
|
value->ty1 = (float)(band->top)
|
||||||
|
/ band->texture_size;
|
||||||
|
value->ty2 = (float)(band->top + height)
|
||||||
|
/ band->texture_size;
|
||||||
|
value->draw_x = draw_x;
|
||||||
|
value->draw_y = draw_y;
|
||||||
|
value->draw_width = width;
|
||||||
|
value->draw_height = height;
|
||||||
|
|
||||||
|
g_hash_table_insert (cache->hash_table, key, value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
78
pango/cogl-pango-glyph-cache.h
Normal file
78
pango/cogl-pango-glyph-cache.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COGL_PANGO_GLYPH_CACHE_H__
|
||||||
|
#define __COGL_PANGO_GLYPH_CACHE_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
#include <pango/pango-font.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _CoglPangoGlyphCache CoglPangoGlyphCache;
|
||||||
|
typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue;
|
||||||
|
|
||||||
|
struct _CoglPangoGlyphCacheValue
|
||||||
|
{
|
||||||
|
CoglHandle texture;
|
||||||
|
|
||||||
|
float tx1;
|
||||||
|
float ty1;
|
||||||
|
float tx2;
|
||||||
|
float ty2;
|
||||||
|
|
||||||
|
int draw_x;
|
||||||
|
int draw_y;
|
||||||
|
int draw_width;
|
||||||
|
int draw_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
CoglPangoGlyphCache *
|
||||||
|
cogl_pango_glyph_cache_new (void);
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache);
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheValue *
|
||||||
|
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyph glyph);
|
||||||
|
|
||||||
|
CoglPangoGlyphCacheValue *
|
||||||
|
cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyph glyph,
|
||||||
|
gconstpointer pixels,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int stride,
|
||||||
|
int draw_x,
|
||||||
|
int draw_y);
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __COGL_PANGO_GLYPH_CACHE_H__ */
|
38
pango/cogl-pango-private.h
Normal file
38
pango/cogl-pango-private.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COGL_PANGO_PRIVATE_H__
|
||||||
|
#define __COGL_PANGO_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "cogl-pango.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
void _cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer);
|
||||||
|
void _cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer,
|
||||||
|
gboolean value);
|
||||||
|
gboolean _cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __COGL_PANGO_PRIVATE_H__ */
|
697
pango/cogl-pango-render.c
Normal file
697
pango/cogl-pango-render.c
Normal file
@ -0,0 +1,697 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PANGO_ENABLE_BACKEND
|
||||||
|
#define PANGO_ENABLE_BACKEND 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pango/pango-fontmap.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
#include <pango/pango-renderer.h>
|
||||||
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#include "cogl-pango-private.h"
|
||||||
|
#include "cogl-pango-glyph-cache.h"
|
||||||
|
#include "cogl-pango-display-list.h"
|
||||||
|
|
||||||
|
struct _CoglPangoRenderer
|
||||||
|
{
|
||||||
|
PangoRenderer parent_instance;
|
||||||
|
|
||||||
|
/* The material used to texture from the glyph cache with */
|
||||||
|
CoglHandle glyph_material;
|
||||||
|
/* The material used for solid fills. (boxes, rectangles + trapezoids) */
|
||||||
|
CoglHandle solid_material;
|
||||||
|
|
||||||
|
/* Caches of glyphs as textures */
|
||||||
|
CoglPangoGlyphCache *glyph_cache;
|
||||||
|
|
||||||
|
/* The current display list that is being built */
|
||||||
|
CoglPangoDisplayList *display_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _CoglPangoRendererClass
|
||||||
|
{
|
||||||
|
PangoRendererClass class_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _CoglPangoRendererQdata CoglPangoRendererQdata;
|
||||||
|
|
||||||
|
/* An instance of this struct gets attached to each PangoLayout to
|
||||||
|
cache the VBO and to detect changes to the layout */
|
||||||
|
struct _CoglPangoRendererQdata
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv,
|
||||||
|
CoglPangoGlyphCacheValue *cache_value,
|
||||||
|
float x1,
|
||||||
|
float y1)
|
||||||
|
{
|
||||||
|
float x2, y2;
|
||||||
|
|
||||||
|
g_return_if_fail (priv->display_list != NULL);
|
||||||
|
|
||||||
|
x2 = x1 + (float) cache_value->draw_width;
|
||||||
|
y2 = y1 + (float) cache_value->draw_height;
|
||||||
|
|
||||||
|
_cogl_pango_display_list_add_texture (priv->display_list,
|
||||||
|
cache_value->texture,
|
||||||
|
x1, y1, x2, y2,
|
||||||
|
cache_value->tx1,
|
||||||
|
cache_value->ty1,
|
||||||
|
cache_value->tx2,
|
||||||
|
cache_value->ty2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cogl_pango_renderer_finalize (GObject *object);
|
||||||
|
static void cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyphString *glyphs,
|
||||||
|
int x,
|
||||||
|
int y);
|
||||||
|
static void cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer,
|
||||||
|
PangoRenderPart part,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
static void cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer,
|
||||||
|
PangoRenderPart part,
|
||||||
|
double y1,
|
||||||
|
double x11,
|
||||||
|
double x21,
|
||||||
|
double y2,
|
||||||
|
double x12,
|
||||||
|
double x22);
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CoglPangoRenderer, cogl_pango_renderer, PANGO_TYPE_RENDERER);
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_renderer_init (CoglPangoRenderer *priv)
|
||||||
|
{
|
||||||
|
priv->glyph_material = cogl_material_new ();
|
||||||
|
|
||||||
|
/* The default combine mode of materials is to modulate (A x B) the texture
|
||||||
|
* RGBA channels with the RGBA channels of the previous layer (which in our
|
||||||
|
* case is just the font color)
|
||||||
|
*
|
||||||
|
* Since the RGB for an alpha texture is defined as 0, this gives us:
|
||||||
|
*
|
||||||
|
* result.rgb = color.rgb * 0
|
||||||
|
* result.a = color.a * texture.a
|
||||||
|
*
|
||||||
|
* What we want is premultiplied rgba values:
|
||||||
|
*
|
||||||
|
* result.rgba = color.rgb * texture.a
|
||||||
|
* result.a = color.a * texture.a
|
||||||
|
*/
|
||||||
|
cogl_material_set_layer_combine (priv->glyph_material, 0, /* layer */
|
||||||
|
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
priv->solid_material = cogl_material_new ();
|
||||||
|
|
||||||
|
priv->glyph_cache = cogl_pango_glyph_cache_new ();
|
||||||
|
|
||||||
|
_cogl_pango_renderer_set_use_mipmapping (priv, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_renderer_class_init (CoglPangoRendererClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cogl_pango_renderer_finalize;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_renderer_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object);
|
||||||
|
|
||||||
|
cogl_pango_glyph_cache_free (priv->glyph_cache);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CoglPangoRenderer *
|
||||||
|
cogl_pango_get_renderer_from_context (PangoContext *context)
|
||||||
|
{
|
||||||
|
PangoFontMap *font_map;
|
||||||
|
PangoRenderer *renderer;
|
||||||
|
CoglPangoFontMap *font_map_priv;
|
||||||
|
|
||||||
|
font_map = pango_context_get_font_map (context);
|
||||||
|
g_return_val_if_fail (COGL_PANGO_IS_FONT_MAP (font_map), NULL);
|
||||||
|
|
||||||
|
font_map_priv = COGL_PANGO_FONT_MAP (font_map);
|
||||||
|
renderer = cogl_pango_font_map_get_renderer (font_map_priv);
|
||||||
|
g_return_val_if_fail (COGL_PANGO_IS_RENDERER (renderer), NULL);
|
||||||
|
|
||||||
|
return COGL_PANGO_RENDERER (renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GQuark
|
||||||
|
cogl_pango_render_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_render_qdata_destroy (CoglPangoRendererQdata *qdata)
|
||||||
|
{
|
||||||
|
if (qdata->display_list)
|
||||||
|
_cogl_pango_display_list_free (qdata->display_list);
|
||||||
|
if (qdata->first_line)
|
||||||
|
pango_layout_line_unref (qdata->first_line);
|
||||||
|
g_slice_free (CoglPangoRendererQdata, qdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_render_layout_subpixel:
|
||||||
|
* @layout: a #PangoLayout
|
||||||
|
* @x: FIXME
|
||||||
|
* @y: FIXME
|
||||||
|
* @color: color to use when rendering the layout
|
||||||
|
* @flags: flags to pass to the renderer
|
||||||
|
*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_render_layout_subpixel (PangoLayout *layout,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
PangoContext *context;
|
||||||
|
CoglPangoRenderer *priv;
|
||||||
|
CoglPangoRendererQdata *qdata;
|
||||||
|
|
||||||
|
context = pango_layout_get_context (layout);
|
||||||
|
priv = cogl_pango_get_renderer_from_context (context);
|
||||||
|
if (G_UNLIKELY (!priv))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qdata = g_object_get_qdata (G_OBJECT (layout),
|
||||||
|
cogl_pango_render_get_qdata_key ());
|
||||||
|
|
||||||
|
if (qdata == NULL)
|
||||||
|
{
|
||||||
|
qdata = g_slice_new0 (CoglPangoRendererQdata);
|
||||||
|
g_object_set_qdata_full (G_OBJECT (layout),
|
||||||
|
cogl_pango_render_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_display_list_free (qdata->display_list);
|
||||||
|
qdata->display_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qdata->display_list == NULL)
|
||||||
|
{
|
||||||
|
qdata->display_list = _cogl_pango_display_list_new ();
|
||||||
|
|
||||||
|
priv->display_list = qdata->display_list;
|
||||||
|
pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0);
|
||||||
|
priv->display_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cogl_push_matrix ();
|
||||||
|
cogl_translate (x / (gfloat) PANGO_SCALE, y / (gfloat) PANGO_SCALE, 0);
|
||||||
|
_cogl_pango_display_list_render (qdata->display_list,
|
||||||
|
color,
|
||||||
|
priv->glyph_material,
|
||||||
|
priv->solid_material);
|
||||||
|
cogl_pop_matrix ();
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_render_layout:
|
||||||
|
* @layout: a #PangoLayout
|
||||||
|
* @x: X coordinate to render the layout at
|
||||||
|
* @y: Y coordinate to render the layout at
|
||||||
|
* @color: color to use when rendering the layout
|
||||||
|
* @flags: flags to pass to the renderer
|
||||||
|
*
|
||||||
|
* Renders @layout.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_render_layout (PangoLayout *layout,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
cogl_pango_render_layout_subpixel (layout,
|
||||||
|
x * PANGO_SCALE,
|
||||||
|
y * PANGO_SCALE,
|
||||||
|
color,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pango_render_layout_line:
|
||||||
|
* @line: a #PangoLayoutLine
|
||||||
|
* @x: X coordinate to render the line at
|
||||||
|
* @y: Y coordinate to render the line at
|
||||||
|
* @color: color to use when rendering the line
|
||||||
|
*
|
||||||
|
* Renders @line at the given coordinates using the given color.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pango_render_layout_line (PangoLayoutLine *line,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color)
|
||||||
|
{
|
||||||
|
PangoContext *context;
|
||||||
|
CoglPangoRenderer *priv;
|
||||||
|
|
||||||
|
context = pango_layout_get_context (line->layout);
|
||||||
|
priv = cogl_pango_get_renderer_from_context (context);
|
||||||
|
if (G_UNLIKELY (!priv))
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->display_list = _cogl_pango_display_list_new ();
|
||||||
|
|
||||||
|
pango_renderer_draw_layout_line (PANGO_RENDERER (priv), line, x, y);
|
||||||
|
|
||||||
|
_cogl_pango_display_list_render (priv->display_list,
|
||||||
|
color,
|
||||||
|
priv->glyph_material,
|
||||||
|
priv->solid_material);
|
||||||
|
|
||||||
|
_cogl_pango_display_list_free (priv->display_list);
|
||||||
|
priv->display_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer)
|
||||||
|
{
|
||||||
|
cogl_pango_glyph_cache_clear (renderer->glyph_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer,
|
||||||
|
gboolean value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
cogl_material_set_layer_filters (renderer->glyph_material, 0,
|
||||||
|
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR,
|
||||||
|
COGL_MATERIAL_FILTER_LINEAR);
|
||||||
|
else
|
||||||
|
cogl_material_set_layer_filters (renderer->glyph_material, 0,
|
||||||
|
COGL_MATERIAL_FILTER_LINEAR,
|
||||||
|
COGL_MATERIAL_FILTER_LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer)
|
||||||
|
{
|
||||||
|
const GList *layers = cogl_material_get_layers (renderer->glyph_material);
|
||||||
|
|
||||||
|
g_return_val_if_fail (layers != NULL, FALSE);
|
||||||
|
|
||||||
|
return (cogl_material_layer_get_min_filter (layers->data)
|
||||||
|
== COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CoglPangoGlyphCacheValue *
|
||||||
|
cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer,
|
||||||
|
PangoFont *font,
|
||||||
|
PangoGlyph glyph)
|
||||||
|
{
|
||||||
|
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
|
||||||
|
CoglPangoGlyphCacheValue *value;
|
||||||
|
|
||||||
|
value = cogl_pango_glyph_cache_lookup (priv->glyph_cache, font, glyph);
|
||||||
|
if (value == NULL)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
cairo_t *cr;
|
||||||
|
cairo_scaled_font_t *scaled_font;
|
||||||
|
PangoRectangle ink_rect;
|
||||||
|
cairo_glyph_t cairo_glyph;
|
||||||
|
|
||||||
|
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
|
||||||
|
pango_extents_to_pixels (&ink_rect, NULL);
|
||||||
|
|
||||||
|
surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
|
||||||
|
ink_rect.width,
|
||||||
|
ink_rect.height);
|
||||||
|
cr = cairo_create (surface);
|
||||||
|
|
||||||
|
scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
|
||||||
|
cairo_set_scaled_font (cr, scaled_font);
|
||||||
|
|
||||||
|
cairo_glyph.x = -ink_rect.x;
|
||||||
|
cairo_glyph.y = -ink_rect.y;
|
||||||
|
/* The PangoCairo glyph numbers directly map to Cairo glyph
|
||||||
|
numbers */
|
||||||
|
cairo_glyph.index = glyph;
|
||||||
|
cairo_show_glyphs (cr, &cairo_glyph, 1);
|
||||||
|
|
||||||
|
cairo_destroy (cr);
|
||||||
|
cairo_surface_flush (surface);
|
||||||
|
|
||||||
|
/* Copy the glyph to the cache */
|
||||||
|
value =
|
||||||
|
cogl_pango_glyph_cache_set (priv->glyph_cache, font, glyph,
|
||||||
|
cairo_image_surface_get_data (surface),
|
||||||
|
cairo_image_surface_get_width (surface),
|
||||||
|
cairo_image_surface_get_height (surface),
|
||||||
|
cairo_image_surface_get_stride (surface),
|
||||||
|
ink_rect.x, ink_rect.y);
|
||||||
|
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
|
COGL_NOTE (PANGO, "cache fail %i", glyph);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
COGL_NOTE (PANGO, "cache success %i", glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout)
|
||||||
|
{
|
||||||
|
PangoContext *context;
|
||||||
|
PangoRenderer *renderer;
|
||||||
|
PangoLayoutIter *iter;
|
||||||
|
|
||||||
|
g_return_if_fail (PANGO_IS_LAYOUT (layout));
|
||||||
|
|
||||||
|
if ((iter = pango_layout_get_iter (layout)) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context = pango_layout_get_context (layout);
|
||||||
|
renderer =
|
||||||
|
PANGO_RENDERER (cogl_pango_get_renderer_from_context (context));
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PangoLayoutLine *line;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
line = pango_layout_iter_get_line_readonly (iter);
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
cogl_pango_renderer_get_cached_glyph (renderer,
|
||||||
|
run->item->analysis.font,
|
||||||
|
gi->glyph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pango_layout_iter_next_line (iter));
|
||||||
|
|
||||||
|
pango_layout_iter_free (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer,
|
||||||
|
PangoRenderPart part)
|
||||||
|
{
|
||||||
|
PangoColor *pango_color = pango_renderer_get_color (renderer, part);
|
||||||
|
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
|
||||||
|
|
||||||
|
if (pango_color)
|
||||||
|
{
|
||||||
|
CoglColor color;
|
||||||
|
|
||||||
|
cogl_color_set_from_4ub (&color,
|
||||||
|
pango_color->red >> 8,
|
||||||
|
pango_color->green >> 8,
|
||||||
|
pango_color->blue >> 8,
|
||||||
|
0xff);
|
||||||
|
|
||||||
|
_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 = ((xin * matrix->xx + yin * matrix->xy)
|
||||||
|
/ PANGO_SCALE + matrix->x0);
|
||||||
|
*yout = ((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);
|
||||||
|
float points[8];
|
||||||
|
|
||||||
|
g_return_if_fail (priv->display_list != NULL);
|
||||||
|
|
||||||
|
points[0] = (x11);
|
||||||
|
points[1] = (y1);
|
||||||
|
points[2] = (x12);
|
||||||
|
points[3] = (y2);
|
||||||
|
points[4] = (x22);
|
||||||
|
points[5] = points[3];
|
||||||
|
points[6] = (x21);
|
||||||
|
points[7] = points[1];
|
||||||
|
|
||||||
|
cogl_pango_renderer_set_color_for_part (renderer, part);
|
||||||
|
|
||||||
|
_cogl_pango_display_list_add_trapezoid (priv->display_list,
|
||||||
|
y1,
|
||||||
|
x11,
|
||||||
|
x21,
|
||||||
|
y2,
|
||||||
|
x12,
|
||||||
|
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;
|
||||||
|
|
||||||
|
cogl_pango_renderer_set_color_for_part (renderer,
|
||||||
|
PANGO_RENDER_PART_FOREGROUND);
|
||||||
|
|
||||||
|
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||||
|
{
|
||||||
|
PangoGlyphInfo *gi = glyphs->glyphs + i;
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
PangoFontMetrics *metrics;
|
||||||
|
|
||||||
|
if (font == NULL ||
|
||||||
|
(metrics = pango_font_get_metrics (font, NULL)) == NULL)
|
||||||
|
{
|
||||||
|
cogl_pango_renderer_draw_box (renderer,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
PANGO_UNKNOWN_GLYPH_WIDTH,
|
||||||
|
PANGO_UNKNOWN_GLYPH_HEIGHT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cogl_pango_renderer_draw_box (renderer,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
metrics->approximate_char_width
|
||||||
|
/ PANGO_SCALE,
|
||||||
|
metrics->ascent / PANGO_SCALE);
|
||||||
|
|
||||||
|
pango_font_metrics_unref (metrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Get the texture containing the glyph. This will create
|
||||||
|
the cache entry if there isn't already one */
|
||||||
|
cache_value =
|
||||||
|
cogl_pango_renderer_get_cached_glyph (renderer,
|
||||||
|
font,
|
||||||
|
gi->glyph);
|
||||||
|
|
||||||
|
if (cache_value == NULL)
|
||||||
|
cogl_pango_renderer_draw_box (renderer,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
PANGO_UNKNOWN_GLYPH_WIDTH,
|
||||||
|
PANGO_UNKNOWN_GLYPH_HEIGHT);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float width, height;
|
||||||
|
|
||||||
|
x += (float)(cache_value->draw_x);
|
||||||
|
y += (float)(cache_value->draw_y);
|
||||||
|
|
||||||
|
width = x + (float)(cache_value->draw_width);
|
||||||
|
height = y + (float)(cache_value->draw_height);
|
||||||
|
|
||||||
|
cogl_pango_renderer_draw_glyph (priv, cache_value, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xi += gi->geometry.width;
|
||||||
|
}
|
||||||
|
}
|
85
pango/cogl-pango.h
Normal file
85
pango/cogl-pango.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 OpenedHand
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PANGO_CLUTTER_H__
|
||||||
|
#define __PANGO_CLUTTER_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <pango/pango.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* It's too difficult to actually subclass the pango cairo font
|
||||||
|
* map. Instead we just make a fake set of macros that actually just
|
||||||
|
* directly use the original type
|
||||||
|
*/
|
||||||
|
#define COGL_PANGO_TYPE_FONT_MAP PANGO_TYPE_CAIRO_FONT_MAP
|
||||||
|
#define COGL_PANGO_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_FONT_MAP, CoglPangoFontMap))
|
||||||
|
#define COGL_PANGO_IS_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_FONT_MAP))
|
||||||
|
|
||||||
|
typedef PangoCairoFontMap CoglPangoFontMap;
|
||||||
|
|
||||||
|
PangoFontMap * cogl_pango_font_map_new (void);
|
||||||
|
PangoContext * cogl_pango_font_map_create_context (CoglPangoFontMap *fm);
|
||||||
|
void cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
|
||||||
|
double dpi);
|
||||||
|
void cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *fm);
|
||||||
|
void cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout);
|
||||||
|
void cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *fm,
|
||||||
|
gboolean value);
|
||||||
|
gboolean cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *fm);
|
||||||
|
PangoRenderer *cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm);
|
||||||
|
|
||||||
|
#define COGL_PANGO_TYPE_RENDERER (cogl_pango_renderer_get_type ())
|
||||||
|
#define COGL_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRenderer))
|
||||||
|
#define COGL_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass))
|
||||||
|
#define COGL_PANGO_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_RENDERER))
|
||||||
|
#define COGL_PANGO_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COGL_PANGO_TYPE_RENDERER))
|
||||||
|
#define COGL_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass))
|
||||||
|
|
||||||
|
/* opaque types */
|
||||||
|
typedef struct _CoglPangoRenderer CoglPangoRenderer;
|
||||||
|
typedef struct _CoglPangoRendererClass CoglPangoRendererClass;
|
||||||
|
|
||||||
|
GType cogl_pango_renderer_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
void cogl_pango_render_layout_subpixel (PangoLayout *layout,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color,
|
||||||
|
int flags);
|
||||||
|
void cogl_pango_render_layout (PangoLayout *layout,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color,
|
||||||
|
int flags);
|
||||||
|
void cogl_pango_render_layout_line (PangoLayoutLine *line,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
const CoglColor *color);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __PANGO_CLUTTER_H__ */
|
Loading…
x
Reference in New Issue
Block a user