[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
10 changed files with 1980 additions and 1 deletions
|
@ -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…
Add table
Reference in a new issue