From e9cceac1ee77d8a47bcb64eb30ea330bc763a7c9 Mon Sep 17 00:00:00 2001 From: Matthew Allum Date: Tue, 3 Oct 2006 21:59:30 +0000 Subject: [PATCH] 2006-10-03 Matthew Allum * configure.ac: * clutter/Makefile.am: * clutter/clutter-actor.c: * clutter/clutter-label.c: * clutter/clutter-label.h: * clutter/pango/Makefile.am: * clutter/pango/pangoclutter-font.c: * clutter/pango/pangoclutter-fontmap.c: * clutter/pango/pangoclutter-private.h: * clutter/pango/pangoclutter-render.c: * clutter/pango/pangoclutter.h: Add initial rough new pango renderer and clutter-label. * examples/super-oh.c: * examples/test.c: Minor fixups --- ChangeLog | 19 + clutter/Makefile.am | 9 +- clutter/clutter-actor.c | 3 - clutter/clutter-label.c | 753 ++++++++++++++++++++------- clutter/clutter-label.h | 64 ++- clutter/pango/Makefile.am | 18 + clutter/pango/pangoclutter-font.c | 467 +++++++++++++++++ clutter/pango/pangoclutter-fontmap.c | 213 ++++++++ clutter/pango/pangoclutter-private.h | 121 +++++ clutter/pango/pangoclutter-render.c | 584 +++++++++++++++++++++ clutter/pango/pangoclutter.h | 97 ++++ configure.ac | 1 + examples/super-oh.c | 4 +- examples/test.c | 11 +- 14 files changed, 2167 insertions(+), 197 deletions(-) create mode 100644 clutter/pango/Makefile.am create mode 100644 clutter/pango/pangoclutter-font.c create mode 100644 clutter/pango/pangoclutter-fontmap.c create mode 100644 clutter/pango/pangoclutter-private.h create mode 100644 clutter/pango/pangoclutter-render.c create mode 100644 clutter/pango/pangoclutter.h diff --git a/ChangeLog b/ChangeLog index 3abfd6320..09a02a8ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2006-10-03 Matthew Allum + + * configure.ac: + * clutter/Makefile.am: + * clutter/clutter-actor.c: + * clutter/clutter-label.c: + * clutter/clutter-label.h: + * clutter/pango/Makefile.am: + * clutter/pango/pangoclutter-font.c: + * clutter/pango/pangoclutter-fontmap.c: + * clutter/pango/pangoclutter-private.h: + * clutter/pango/pangoclutter-render.c: + * clutter/pango/pangoclutter.h: + Add initial rough new pango renderer and clutter-label. + + * examples/super-oh.c: + * examples/test.c: + Minor fixups + 2006-09-20 Matthew Allum * clutter/clutter-actor.c: (clutter_actor_paint): diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 38ff474db..dd54a6f24 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS=pango + MARSHALFILES = clutter-marshal.c clutter-marshal.h ENUMFILES = clutter-enum-types.c clutter-enum-types.h GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` @@ -97,12 +99,15 @@ libclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = $(MARSHALFILES) \ $(source_h) \ $(source_h_priv) -INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ -I$(top_srcdir) +INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ -I$(top_srcdir) -I$(top_srcdir)/clutter/pango lib_LTLIBRARIES = libclutter-@CLUTTER_MAJORMINOR@.la -libclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = @CLUTTER_LIBS@ +libclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = \ + @CLUTTER_LIBS@ $(top_srcdir)/clutter/pango/libpangoclutter.a libclutter_@CLUTTER_MAJORMINOR@_la_LDFLAGS = @CLUTTER_LT_LDFLAGS@ +libclutter_@CLUTTER_MAJORMINOR@_la_DEPENDENCIES = \ + $(top_srcdir)/clutter/pango/libpangoclutter.a clutterheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/clutter clutterheaders_HEADERS = $(source_h) \ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index f648a6ddd..e47028630 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -338,9 +338,6 @@ clutter_actor_paint (ClutterActor *self) if (self->priv->has_clip) { glDisable (GL_STENCIL_TEST); -#if 0 - glDisable (GL_SCISSOR_TEST); -#endif } glPopMatrix(); diff --git a/clutter/clutter-label.c b/clutter/clutter-label.c index a0e137684..99aed1650 100644 --- a/clutter/clutter-label.c +++ b/clutter/clutter-label.c @@ -37,18 +37,28 @@ #include "clutter-enum-types.h" #include "clutter-private.h" /* for DBG */ -#include +#include "pangoclutter.h" #define DEFAULT_FONT_NAME "Sans 10" -G_DEFINE_TYPE (ClutterLabel, clutter_label, CLUTTER_TYPE_TEXTURE); +G_DEFINE_TYPE (ClutterLabel, clutter_label, CLUTTER_TYPE_ACTOR); + +/* Probably move into main */ +static PangoClutterFontMap *_font_map = NULL; +static PangoContext *_context = NULL; enum { PROP_0, PROP_FONT_NAME, PROP_TEXT, - PROP_COLOR + PROP_COLOR, + PROP_ATTRIBUTES, + PROP_USE_MARKUP, + PROP_ALIGNMENT, /* FIXME */ + PROP_WRAP, + PROP_WRAP_MODE, + PROP_ELLIPSIZE, }; #define CLUTTER_LABEL_GET_PRIVATE(obj) \ @@ -56,7 +66,6 @@ enum struct _ClutterLabelPrivate { - PangoLayout *layout; PangoContext *context; PangoFontDescription *desc; @@ -67,97 +76,21 @@ struct _ClutterLabelPrivate gint extents_width; gint extents_height; + + guint alignment : 2; + guint wrap : 1; + guint use_underline : 1; + guint use_markup : 1; + guint ellipsize : 3; + guint single_line_mode : 1; + guint wrap_mode : 3; + + PangoAttrList *attrs; + PangoAttrList *effective_attrs; + PangoLayout *layout; + gint width_chars; }; -static void -clutter_label_make_pixbuf (ClutterLabel *label) -{ - gint bx, by, w, h; - FT_Bitmap ft_bitmap; - guint8 const *ps; - guint8 *pd; - ClutterLabelPrivate *priv; - ClutterTexture *texture; - GdkPixbuf *pixbuf; - - priv = label->priv; - - texture = CLUTTER_TEXTURE(label); - - if (priv->layout == NULL || priv->desc == NULL || priv->text == NULL) - { - CLUTTER_DBG("*** FAIL: layout: %p , desc: %p, text %p ***", - priv->layout, priv->desc, priv->text); - return; - } - - pango_layout_set_font_description (priv->layout, priv->desc); - pango_layout_set_text (priv->layout, priv->text, -1); - - if (priv->extents_width != 0) - { - CLUTTER_DBG("forcing width to '%i'", priv->extents_width); - pango_layout_set_width (priv->layout, PANGO_SCALE * priv->extents_width); - pango_layout_set_wrap (priv->layout, PANGO_WRAP_WORD); - } - - pango_layout_get_pixel_size (priv->layout, - &w, - &h); - - if (w == 0 || h == 0) - { - CLUTTER_DBG("aborting w:%i , h:%i", w, h); - return; - } - - ft_bitmap.rows = h; - ft_bitmap.width = w; - ft_bitmap.pitch = (w+3) & ~3; - ft_bitmap.buffer = g_malloc0 (ft_bitmap.rows * ft_bitmap.pitch); - ft_bitmap.num_grays = 256; - ft_bitmap.pixel_mode = ft_pixel_mode_grays; - ft_bitmap.palette_mode = 0; - ft_bitmap.palette = NULL; - - pango_ft2_render_layout (&ft_bitmap, priv->layout, 0, 0); - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - TRUE, - 8, - ft_bitmap.width, - ft_bitmap.rows); - - for (by = 0; by < ft_bitmap.rows; by++) - { - pd = gdk_pixbuf_get_pixels (pixbuf) - + by * gdk_pixbuf_get_rowstride (pixbuf); - ps = ft_bitmap.buffer + by * ft_bitmap.pitch; - - for (bx = 0; bx < ft_bitmap.width; bx++) - { - *pd++ = priv->fgcol.red; - *pd++ = priv->fgcol.green; - *pd++ = priv->fgcol.blue; - *pd++ = *ps++; - } - } - - g_free (ft_bitmap.buffer); - - CLUTTER_DBG("Calling set_pixbuf with text : '%s' , pixb %ix%i" - " rendered with color %i,%i,%i,%i", - priv->text, w, h, - priv->fgcol.red, - priv->fgcol.green, - priv->fgcol.blue, - priv->fgcol.alpha); - - clutter_texture_set_pixbuf (CLUTTER_TEXTURE (label), pixbuf); - - /* Texture has the ref now */ - g_object_unref (pixbuf); -} static void clutter_label_set_property (GObject *object, @@ -182,6 +115,24 @@ clutter_label_set_property (GObject *object, case PROP_COLOR: clutter_label_set_color (label, g_value_get_boxed (value)); break; + case PROP_ATTRIBUTES: + clutter_label_set_attributes (label, g_value_get_boxed (value)); + break; + case PROP_ALIGNMENT: + clutter_label_set_alignment (label, g_value_get_enum (value)); + break; + case PROP_USE_MARKUP: + clutter_label_set_use_markup (label, g_value_get_boolean (value)); + break; + case PROP_WRAP: + clutter_label_set_line_wrap (label, g_value_get_boolean (value)); + break; + case PROP_WRAP_MODE: + clutter_label_set_line_wrap_mode (label, g_value_get_enum (value)); + break; + case PROP_ELLIPSIZE: + clutter_label_set_ellipsize (label, g_value_get_enum (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -213,12 +164,124 @@ clutter_label_get_property (GObject *object, clutter_label_get_color (label, &color); g_value_set_boxed (value, &color); break; + case PROP_ATTRIBUTES: + g_value_set_boxed (value, priv->attrs); + break; + case PROP_ALIGNMENT: + g_value_set_enum (value, priv->alignment); + break; + case PROP_USE_MARKUP: + g_value_set_boolean (value, priv->use_markup); + break; + case PROP_WRAP: + g_value_set_boolean (value, priv->wrap); + break; + case PROP_WRAP_MODE: + g_value_set_enum (value, priv->wrap_mode); + break; + case PROP_ELLIPSIZE: + g_value_set_enum (value, priv->ellipsize); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static void +clutter_label_ensure_layout (ClutterLabel *label, gint width) +{ + ClutterLabelPrivate *priv; + + priv = label->priv; + + if (!priv->layout) + { + priv->layout = pango_layout_new (_context); + + if (priv->effective_attrs) + pango_layout_set_attributes (priv->layout, priv->effective_attrs); + + pango_layout_set_alignment (priv->layout, priv->alignment); + pango_layout_set_ellipsize (priv->layout, priv->ellipsize); + pango_layout_set_single_paragraph_mode (priv->layout, + priv->single_line_mode); + + pango_layout_set_font_description (priv->layout, priv->desc); + pango_layout_set_text (priv->layout, priv->text, -1); + + if (priv->wrap) + pango_layout_set_wrap (priv->layout, priv->wrap_mode); + + if ((priv->ellipsize || priv->wrap) && width > 0) + { + pango_layout_set_width (priv->layout, width * PANGO_SCALE); + } + else + pango_layout_set_width (priv->layout, -1); + } +} + +static void +clutter_label_clear_layout (ClutterLabel *label) +{ + if (label->priv->layout) + { + g_object_unref (label->priv->layout); + label->priv->layout = NULL; + } +} + +void +clutter_label_paint (ClutterActor *self) +{ + ClutterLabel *label; + ClutterLabelPrivate *priv; + + label = CLUTTER_LABEL(self); + priv = label->priv; + + if (priv->desc == NULL || priv->text == NULL) + { + CLUTTER_DBG("*** FAIL: layout: %p , desc: %p, text %p ***", + priv->layout, priv->desc, priv->text); + return; + } + + clutter_label_ensure_layout (label, clutter_actor_get_width(self)); + + priv->fgcol.alpha = clutter_actor_get_opacity(self); + + pango_clutter_render_layout (priv->layout, 0, 0, &priv->fgcol, 0); +} + +static void +clutter_label_allocate_coords (ClutterActor *self, + ClutterActorBox *box) +{ + ClutterLabel *label = CLUTTER_LABEL(self); + ClutterLabelPrivate *priv; + PangoRectangle logical_rect; + + priv = label->priv; + + clutter_label_ensure_layout (label, box->x2 - box->x1); + + pango_layout_get_extents (priv->layout, NULL, &logical_rect); + + box->x2 = box->x1 + PANGO_PIXELS (logical_rect.width); + box->y2 = box->y1 + PANGO_PIXELS (logical_rect.height); + + return; +} + +static void +clutter_label_request_coords (ClutterActor *self, + ClutterActorBox *box) +{ + /* do we need to do anything ? */ + clutter_label_clear_layout (CLUTTER_LABEL(self)); +} static void clutter_label_dispose (GObject *object) @@ -266,13 +329,10 @@ clutter_label_class_init (ClutterLabelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - ClutterActorClass *parent_class = CLUTTER_ACTOR_CLASS (clutter_label_parent_class); - actor_class->paint = parent_class->paint; - actor_class->realize = parent_class->realize; - actor_class->unrealize = parent_class->unrealize; - actor_class->show = parent_class->show; - actor_class->hide = parent_class->hide; + actor_class->paint = clutter_label_paint; + actor_class->request_coords = clutter_label_request_coords; + actor_class->allocate_coords = clutter_label_allocate_coords; gobject_class->finalize = clutter_label_finalize; gobject_class->dispose = clutter_label_dispose; @@ -303,6 +363,61 @@ clutter_label_class_init (ClutterLabelClass *klass) CLUTTER_TYPE_COLOR, G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, PROP_ATTRIBUTES, + g_param_spec_boxed ("attributes", + "Attributes", + "A list of style attributes to apply to the" + "text of the label", + PANGO_TYPE_ATTR_LIST, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_USE_MARKUP, + g_param_spec_boolean ("use-markup", + "Use markup", + "The text of the label includes XML markup." + "See pango_parse_markup()", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_WRAP, + g_param_spec_boolean ("wrap", + "Line wrap", + "If set, wrap lines if the text becomes too wide", + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_WRAP_MODE, + g_param_spec_enum ("wrap-mode", + "Line wrap mode", + "If wrap is set, controls how linewrapping is done", + PANGO_TYPE_WRAP_MODE, + PANGO_WRAP_WORD, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_ELLIPSIZE, + g_param_spec_enum ( "ellipsize", + "Ellipsize", + "The preferred place to ellipsize the string," + "if the label does not have enough room to " + "display the entire string", + PANGO_TYPE_ELLIPSIZE_MODE, + PANGO_ELLIPSIZE_NONE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_ALIGNMENT, + g_param_spec_enum ( "alignment", + "Alignment", + "The preferred alignment for the string,", + PANGO_TYPE_ALIGNMENT, + PANGO_ALIGN_LEFT, + G_PARAM_READWRITE)); + g_type_class_add_private (gobject_class, sizeof (ClutterLabelPrivate)); } @@ -310,29 +425,34 @@ static void clutter_label_init (ClutterLabel *self) { ClutterLabelPrivate *priv; - PangoFT2FontMap *font_map; self->priv = priv = CLUTTER_LABEL_GET_PRIVATE (self); - priv->fgcol.red = 0; - priv->fgcol.green = 0; - priv->fgcol.blue = 0; - priv->fgcol.alpha = 255; + if (_context == NULL) + { + _font_map = PANGO_CLUTTER_FONT_MAP (pango_clutter_font_map_new ()); + /* pango_clutter_font_map_set_resolution (font_map, 96.0, 96.0); */ + _context = pango_clutter_font_map_create_context (_font_map); + } - priv->text = NULL; - priv->font_name = g_strdup (DEFAULT_FONT_NAME); - priv->desc = pango_font_description_from_string (priv->font_name); - - font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ()); - pango_ft2_font_map_set_resolution (font_map, 96.0, 96.0); - priv->context = pango_ft2_font_map_create_context (font_map); + priv->alignment = PANGO_ALIGN_LEFT; + priv->wrap = TRUE; + priv->wrap_mode = PANGO_WRAP_WORD; + priv->ellipsize = PANGO_ELLIPSIZE_NONE; + priv->use_underline = FALSE; + priv->use_markup = FALSE; + priv->layout = NULL; + priv->text = NULL; + priv->attrs = NULL; - priv->layout = pango_layout_new (priv->context); + priv->fgcol.red = 0; + priv->fgcol.green = 0; + priv->fgcol.blue = 0; + priv->fgcol.alpha = 255; + + priv->font_name = g_strdup (DEFAULT_FONT_NAME); + priv->desc = pango_font_description_from_string (priv->font_name); - /* See http://bugzilla.gnome.org/show_bug.cgi?id=143542 ?? - pango_ft2_font_map_substitute_changed (font_map); - g_object_unref (font_map); - */ CLUTTER_MARK(); } @@ -354,18 +474,10 @@ clutter_label_new_with_text (const gchar *font_name, CLUTTER_MARK(); label = clutter_label_new (); + clutter_label_set_font_name (CLUTTER_LABEL(label), font_name); clutter_label_set_text (CLUTTER_LABEL(label), text); - /* FIXME: Why does calling like; - * return g_object_new (CLUTTER_TYPE_LABEL, - * "font-name", font_name, - * "text", text, - * NULL); - * mean text does not get rendered without color being set - * ( seems to need extra clutter_label_make_pixbuf() call ) - */ - return label; } @@ -389,7 +501,7 @@ clutter_label_new (void) * Retrieves the text displayed by @label * * Return value: the text of the label. The returned string is - * owned by #ClutterLabel and should not be modified or freed. + * owned by #ClutterLabel and should not be modified or freed. */ G_CONST_RETURN gchar * clutter_label_get_text (ClutterLabel *label) @@ -419,7 +531,7 @@ clutter_label_set_text (ClutterLabel *label, g_free (priv->text); priv->text = g_strdup (text); - clutter_label_make_pixbuf (label); + clutter_label_clear_layout (label); if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); @@ -487,7 +599,7 @@ clutter_label_set_font_name (ClutterLabel *label, if (label->priv->text && label->priv->text[0] != '\0') { - clutter_label_make_pixbuf (label); + clutter_label_clear_layout (label); if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); @@ -496,52 +608,6 @@ clutter_label_set_font_name (ClutterLabel *label, g_object_notify (G_OBJECT (label), "font-name"); } -/** - * clutter_label_set_text_extents: - * @label: a #ClutterLabel - * @width: the width of the text - * @height: the height of the text - * - * Sets the maximum extents of the label's text. - */ -void -clutter_label_set_text_extents (ClutterLabel *label, - gint width, - gint height) -{ - /* FIXME: height extents is broken.... - */ - - label->priv->extents_width = width; - label->priv->extents_height = height; - - clutter_label_make_pixbuf (label); - - if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) - clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); -} - -/** - * clutter_label_get_text_extents: - * @label: a #ClutterLabel - * @width: return location for the width of the extents or %NULL - * @height: return location for the height of the extents or %NULL - * - * Gets the extents of the label. - */ -void -clutter_label_get_text_extents (ClutterLabel *label, - gint *width, - gint *height) -{ - g_return_if_fail (CLUTTER_IS_LABEL (label)); - - if (width) - *width = label->priv->extents_width; - - if (height) - *height = label->priv->extents_height; -} /** * clutter_label_set_color: @@ -566,9 +632,8 @@ clutter_label_set_color (ClutterLabel *label, priv->fgcol.blue = color->blue; priv->fgcol.alpha = color->alpha; - clutter_label_make_pixbuf (label); - actor = CLUTTER_ACTOR (label); + clutter_actor_set_opacity (actor, priv->fgcol.alpha); if (CLUTTER_ACTOR_IS_VISIBLE (actor)) @@ -601,3 +666,339 @@ clutter_label_get_color (ClutterLabel *label, color->blue = priv->fgcol.blue; color->alpha = priv->fgcol.alpha; } + +/** + * clutter_label_set_ellipsize: + * @label: a #ClutterLabel + * @mode: a #PangoEllipsizeMode + * + * Sets the mode used to ellipsize (add an ellipsis: "...") to the text + * if there is not enough space to render the entire string. + * + * Since: 0.2 + **/ +void +clutter_label_set_ellipsize (ClutterLabel *label, + PangoEllipsizeMode mode) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE + && mode <= PANGO_ELLIPSIZE_END); + + if ((PangoEllipsizeMode) label->priv->ellipsize != mode) + { + label->priv->ellipsize = mode; + + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + } +} + +/** + * clutter_label_get_ellipsize: + * @label: a #ClutterLabel + * + * Returns the ellipsizing position of the label. + * See clutter_label_set_ellipsize(). + * + * Return value: #PangoEllipsizeMode + * + * Since: 0.2 + **/ +PangoEllipsizeMode +clutter_label_get_ellipsize (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), PANGO_ELLIPSIZE_NONE); + + return label->priv->ellipsize; +} + +/** + * clutter_label_set_line_wrap: + * @label: a #ClutterLabel + * @wrap: the setting + * + * Toggles line wrapping within the #ClutterLabel widget. %TRUE makes it break + * lines if text exceeds the widget's size. %FALSE lets the text get cut off + * by the edge of the widget if it exceeds the widget size. + * + * Note that setting line wrapping to %TRUE does not make the label + * wrap at its parent container's width, because CLUTTER+ widgets + * conceptually can't make their requisition depend on the parent + * container's size. For a label that wraps at a specific position, + * set the label's width using clutter_widget_set_size_request(). + **/ +void +clutter_label_set_line_wrap (ClutterLabel *label, + gboolean wrap) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + + wrap = wrap != FALSE; + + if (label->priv->wrap != wrap) + { + label->priv->wrap = wrap; + + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + + g_object_notify (G_OBJECT (label), "wrap"); + } +} + +/** + * clutter_label_get_line_wrap: + * @label: a #ClutterLabel + * + * Returns whether lines in the label are automatically wrapped. + * See clutter_label_set_line_wrap (). + * + * Return value: %TRUE if the lines of the label are automatically wrapped. + * + * Since: 0.2 + */ +gboolean +clutter_label_get_line_wrap (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE); + + return label->priv->wrap; +} + +/** + * clutter_label_set_line_wrap_mode: + * @label: a #ClutterLabel + * @wrap_mode: the line wrapping mode + * + * If line wrapping is on (see clutter_label_set_line_wrap()) this controls how + * the line wrapping is done. The default is %PANGO_WRAP_WORD which means + * wrap on word boundaries. + * + * Since: 0.2 + **/ +void +clutter_label_set_line_wrap_mode (ClutterLabel *label, + PangoWrapMode wrap_mode) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + + if (label->priv->wrap_mode != wrap_mode) + { + label->priv->wrap_mode = wrap_mode; + + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + + g_object_notify (G_OBJECT (label), "wrap-mode"); + } +} + +/** + * clutter_label_get_line_wrap_mode: + * @label: a #ClutterLabel + * + * Returns line wrap mode used by the label. See clutter_label_set_line_wrap_mode (). + * + * Return value: %TRUE if the lines of the label are automatically wrapped. + * + * Since: 0.2 + */ +PangoWrapMode +clutter_label_get_line_wrap_mode (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE); + + return label->priv->wrap_mode; +} + +/** + * clutter_label_get_layout: + * @label: a #ClutterLabel + * + * Gets the #PangoLayout used to display the label. + * The layout is useful to e.g. convert text positions to + * pixel positions. + * The returned layout is owned by the label so need not be + * freed by the caller. + * + * Return value: the #PangoLayout for this label + * + * Since: 0.2 + **/ +PangoLayout* +clutter_label_get_layout (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL); + + clutter_label_ensure_layout (label, -1); + + return label->priv->layout; +} + +static void +clutter_label_set_attributes_internal (ClutterLabel *label, + PangoAttrList *attrs) +{ + ClutterLabelPrivate *priv; + + priv = label->priv; + + if (attrs) + pango_attr_list_ref (attrs); + + if (priv->attrs) + pango_attr_list_unref (priv->attrs); + + if (!priv->use_markup) + { + if (attrs) + pango_attr_list_ref (attrs); + if (priv->effective_attrs) + pango_attr_list_unref (priv->effective_attrs); + priv->effective_attrs = attrs; + } + + label->priv->attrs = attrs; + g_object_notify (G_OBJECT (label), "attributes"); +} + +/** + * clutter_label_set_attributes: + * @label: a #ClutterLabel + * @attrs: a #PangoAttrList + * + * Sets a #PangoAttrList; the attributes in the list are applied to the + * label text. The attributes set with this function will be ignored + * if the "use_markup" property + * is %TRUE. + * + * Since: 0.2 + **/ +void +clutter_label_set_attributes (ClutterLabel *label, + PangoAttrList *attrs) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + + clutter_label_set_attributes_internal (label, attrs); + + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); +} + +/** + * clutter_label_get_attributes: + * @label: a #ClutterLabel + * + * Gets the attribute list that was set on the label using + * clutter_label_set_attributes(), if any. + * + * Return value: the attribute list, or %NULL if none was set. + * + * Since: 0.2 + **/ +PangoAttrList * +clutter_label_get_attributes (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL); + + return label->priv->attrs; +} + +/** + * clutter_label_set_use_markup: + * @label: a #ClutterLabel + * @setting: %TRUE if the label's text should be parsed for markup. + * + * Sets whether the text of the label contains markup in Pango's text markup + * language. See clutter_label_set_markup(). + **/ +void +clutter_label_set_use_markup (ClutterLabel *label, + gboolean setting) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + + if (label->priv->use_markup != setting) + { + label->priv->use_markup = setting; + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + + g_object_notify (G_OBJECT (label), "use-markup"); + } +} + +/** + * clutter_label_get_use_markup: + * @label: a #ClutterLabel + * + * Returns whether the label's text is interpreted as marked up with + * the Pango text markup + * language. See clutter_label_set_use_markup (). + * + * Return value: %TRUE if the label's text will be parsed for markup. + **/ +gboolean +clutter_label_get_use_markup (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE); + + return label->priv->use_markup; +} + +/** + * clutter_label_set_alignment: + * @label: a #ClutterLabel + * @alignment: A #PangoAlignment + * + * Sets text alignment of the label. + **/ +void +clutter_label_set_alignment (ClutterLabel *label, + PangoAlignment alignment) +{ + g_return_if_fail (CLUTTER_IS_LABEL (label)); + + if (label->priv->alignment != alignment) + { + label->priv->alignment = alignment; + clutter_label_clear_layout (label); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + + g_object_notify (G_OBJECT (label), "alignment"); + } +} + +/** + * clutter_label_get_alignment: + * @label: a #ClutterLabel + * + * Returns the label's text alignment + * + * Return value: The labels #PangoAlignment + * + * Since 0.2 + **/ +gboolean +clutter_label_get_alignment (ClutterLabel *label) +{ + g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE); + + return label->priv->alignment; +} + diff --git a/clutter/clutter-label.h b/clutter/clutter-label.h index ec1916d96..9ffdfe8f8 100644 --- a/clutter/clutter-label.h +++ b/clutter/clutter-label.h @@ -31,6 +31,9 @@ #include #include +#include + + G_BEGIN_DECLS #define CLUTTER_TYPE_LABEL clutter_label_get_type() @@ -61,7 +64,7 @@ typedef struct _ClutterLabelPrivate ClutterLabelPrivate; struct _ClutterLabel { - ClutterTexture parent; + ClutterActor parent; /*< private >*/ ClutterLabelPrivate *priv; @@ -70,7 +73,7 @@ struct _ClutterLabel struct _ClutterLabelClass { /*< private >*/ - ClutterTextureClass parent_class; + ClutterActorClass parent_class; void (*_clutter_label_1) (void); void (*_clutter_label_2) (void); @@ -80,11 +83,11 @@ struct _ClutterLabelClass GType clutter_label_get_type (void) G_GNUC_CONST; -ClutterActor * clutter_label_new (void); -ClutterActor * clutter_label_new_with_text (const gchar *font_name, +ClutterActor *clutter_label_new (void); +ClutterActor *clutter_label_new_with_text (const gchar *font_name, const gchar *text); -void clutter_label_set_text (ClutterLabel *label, +void clutter_label_set_text (ClutterLabel *label, const gchar *text); G_CONST_RETURN gchar *clutter_label_get_text (ClutterLabel *label); void clutter_label_set_font_name (ClutterLabel *label, @@ -94,12 +97,51 @@ void clutter_label_set_color (ClutterLabel *label, const ClutterColor *color); void clutter_label_get_color (ClutterLabel *label, ClutterColor *color); -void clutter_label_set_text_extents (ClutterLabel *label, - gint width, - gint height); -void clutter_label_get_text_extents (ClutterLabel *label, - gint *width, - gint *height); + +void +clutter_label_set_ellipsize (ClutterLabel *label, + PangoEllipsizeMode mode); + +PangoEllipsizeMode +clutter_label_get_ellipsize (ClutterLabel *label); + +void +clutter_label_set_line_wrap (ClutterLabel *label, + gboolean wrap); + +gboolean +clutter_label_get_line_wrap (ClutterLabel *label); + +void +clutter_label_set_line_wrap_mode (ClutterLabel *label, + PangoWrapMode wrap_mode); + +PangoWrapMode +clutter_label_get_line_wrap_mode (ClutterLabel *label); + +PangoLayout* +clutter_label_get_layout (ClutterLabel *label); + +void +clutter_label_set_attributes (ClutterLabel *label, + PangoAttrList *attrs); + +PangoAttrList* +clutter_label_get_attributes (ClutterLabel *label); + +void +clutter_label_set_use_markup (ClutterLabel *label, + gboolean setting); + +gboolean +clutter_label_get_use_markup (ClutterLabel *label); + +void +clutter_label_set_alignment (ClutterLabel *label, + PangoAlignment alignment); +gboolean +clutter_label_get_alignment (ClutterLabel *label); + G_END_DECLS diff --git a/clutter/pango/Makefile.am b/clutter/pango/Makefile.am new file mode 100644 index 000000000..adb578400 --- /dev/null +++ b/clutter/pango/Makefile.am @@ -0,0 +1,18 @@ +source_c = pangoclutter-font.c \ + pangoclutter-fontmap.c \ + pangoclutter-render.c + +source_h = pangoclutter.h + +source_h_priv = pangoclutter-private.h + +noinst_LIBRARIES = libpangoclutter.a + +libpangoclutter_a_SOURCES = $(source_c) \ + $(source_h) \ + $(source_h_priv) + +INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ -I$(top_srcdir) + +pangoclutterheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/clutter +pangoclutterheaders_HEADERS = $(source_h) diff --git a/clutter/pango/pangoclutter-font.c b/clutter/pango/pangoclutter-font.c new file mode 100644 index 000000000..87ec2994c --- /dev/null +++ b/clutter/pango/pangoclutter-font.c @@ -0,0 +1,467 @@ +/* Pango + * Clutter Freetype2 handling + * + * Copyright (C) 1999 Red Hat Software + * Copyright (C) 2000 Tor Lillqvist + * Copyright (C) 2006 Marc Lehmann + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define PANGO_ENABLE_BACKEND + +#include +#include +#include +#include +#include + +#include "pangoclutter.h" +#include "pangoclutter-private.h" +#include +#include + +#define PANGO_CLUTTER_FONT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + PANGO_TYPE_CLUTTER_FONT, \ + PangoClutterFontClass)) + +#define PANGO_CLUTTER_IS_FONT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_CLUTTER_FONT)) + +#define PANGO_CLUTTER_FONT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + PANGO_TYPE_CLUTTER_FONT, \ + PangoClutterFontClass)) + +typedef struct _PangoClutterFontClass PangoClutterFontClass; + +struct _PangoClutterFontClass +{ + PangoFcFontClass parent_class; +}; + +static void pango_clutter_font_finalize (GObject *object); + +static void pango_clutter_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +static FT_Face pango_clutter_font_real_lock_face (PangoFcFont *font); +static void pango_clutter_font_real_unlock_face (PangoFcFont *font); + +PangoClutterFont * +_pango_clutter_font_new (PangoClutterFontMap *fontmap_, FcPattern *pattern) +{ + PangoFontMap *fontmap = PANGO_FONT_MAP (fontmap_); + PangoClutterFont *font; + double d; + + g_return_val_if_fail (fontmap != NULL, NULL); + g_return_val_if_fail (pattern != NULL, NULL); + + font = (PangoClutterFont *)g_object_new (PANGO_TYPE_CLUTTER_FONT, + "pattern", pattern, + NULL); + + if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch) + font->size = d * PANGO_SCALE; + + return font; +} + +static void +load_fallback_face (PangoClutterFont *font, const char *original_file) +{ + PangoFcFont *fcfont = PANGO_FC_FONT (font); + FcPattern *sans; + FcPattern *matched; + FcResult result; + FT_Error error; + FcChar8 *filename2 = NULL; + gchar *name; + int id; + + sans = FcPatternBuild + (NULL, + FC_FAMILY, FcTypeString, "sans", + FC_PIXEL_SIZE, FcTypeDouble, (double)font->size / PANGO_SCALE, + NULL); + + matched = FcFontMatch (NULL, sans, &result); + + if (FcPatternGetString (matched, FC_FILE, 0, &filename2) != FcResultMatch) + goto bail1; + + if (FcPatternGetInteger (matched, FC_INDEX, 0, &id) != FcResultMatch) + goto bail1; + + error = FT_New_Face (_pango_clutter_font_map_get_library (fcfont->fontmap), + (char *) filename2, id, &font->face); + + if (error) + { + bail1: + name = pango_font_description_to_string (fcfont->description); + g_warning ("Unable to open font file %s for font %s, exiting\n", + filename2, name); + exit (1); + } + else + { + name = pango_font_description_to_string (fcfont->description); + g_warning ("Unable to open font file %s for font %s, falling back to %s\n", original_file, name, filename2); + g_free (name); + } + + FcPatternDestroy (sans); + FcPatternDestroy (matched); +} + +static void +set_transform (PangoClutterFont *font) +{ + PangoFcFont *fcfont = (PangoFcFont *)font; + FcMatrix *fc_matrix; + + if (FcPatternGetMatrix (fcfont->font_pattern, + FC_MATRIX, + 0, + &fc_matrix) == FcResultMatch) + { + FT_Matrix ft_matrix; + + ft_matrix.xx = 0x10000L * fc_matrix->xx; + ft_matrix.yy = 0x10000L * fc_matrix->yy; + ft_matrix.xy = 0x10000L * fc_matrix->xy; + ft_matrix.yx = 0x10000L * fc_matrix->yx; + + FT_Set_Transform (font->face, &ft_matrix, NULL); + } +} + +FT_Face +pango_clutter_font_get_face (PangoFont *font) +{ + PangoClutterFont *glfont = (PangoClutterFont *)font; + PangoFcFont *fcfont = (PangoFcFont *)font; + FcPattern *pattern; + FcChar8 *filename; + FcBool antialias, hinting, autohint; + FT_Error error; + int id; + + pattern = fcfont->font_pattern; + + if (!glfont->face) + { + glfont->load_flags = 0; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, FC_ANTIALIAS, + 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + glfont->load_flags |= FT_LOAD_NO_BITMAP; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, FC_HINTING, + 0, &hinting) != FcResultMatch) + hinting = FcTrue; + + if (!hinting) + glfont->load_flags |= FT_LOAD_NO_HINTING; + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, FC_AUTOHINT, + 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + glfont->load_flags |= FT_LOAD_FORCE_AUTOHINT; + + if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch) + goto bail0; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) + goto bail0; + + error + = FT_New_Face (_pango_clutter_font_map_get_library (fcfont->fontmap), + (char *)filename, id, &glfont->face); + + if (error != FT_Err_Ok) + { + bail0: + load_fallback_face (glfont, (char *)filename); + } + + g_assert (glfont->face); + + set_transform (glfont); + + error = FT_Set_Char_Size (glfont->face, + PANGO_PIXELS_26_6 (glfont->size), + PANGO_PIXELS_26_6 (glfont->size), + 0, 0); + if (error) + g_warning ("Error in FT_Set_Char_Size: %d", error); + } + + return glfont->face; +} + +G_DEFINE_TYPE (PangoClutterFont, pango_clutter_font, PANGO_TYPE_FC_FONT) + +static void +pango_clutter_font_init (PangoClutterFont *font) +{ + font->face = NULL; + font->size = 0; + font->glyph_info = g_hash_table_new (NULL, NULL); +} + +static void +pango_clutter_font_class_init (PangoClutterFontClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontClass *font_class = PANGO_FONT_CLASS (class); + PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (class); + + object_class->finalize = pango_clutter_font_finalize; + + font_class->get_glyph_extents = pango_clutter_font_get_glyph_extents; + + fc_font_class->lock_face = pango_clutter_font_real_lock_face; + fc_font_class->unlock_face = pango_clutter_font_real_unlock_face; +} + +static PangoClutterGlyphInfo * +pango_clutter_font_get_glyph_info (PangoFont *font_, + PangoGlyph glyph, + gboolean create) +{ + PangoClutterFont *font = (PangoClutterFont *)font_; + PangoFcFont *fcfont = (PangoFcFont *)font; + PangoClutterGlyphInfo *info; + + info = g_hash_table_lookup (font->glyph_info, GUINT_TO_POINTER (glyph)); + + if ((info == NULL) && create) + { + info = g_slice_new0 (PangoClutterGlyphInfo); + + pango_fc_font_get_raw_extents (fcfont, font->load_flags, + glyph, + &info->ink_rect, + &info->logical_rect); + + g_hash_table_insert (font->glyph_info, GUINT_TO_POINTER(glyph), info); + } + + return info; +} + +PangoGlyph +pango_clutter_get_unknown_glyph (PangoFont *font) +{ + FT_Face face = pango_clutter_font_get_face (font); + + if (face && FT_IS_SFNT (face)) + /* TrueType fonts have an 'unknown glyph' box on glyph index 0 */ + return 0; + else + return PANGO_GLYPH_EMPTY; +} + +static void +pango_clutter_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + PangoClutterGlyphInfo *info; + + if (glyph == PANGO_GLYPH_EMPTY) + { + if (ink_rect) + ink_rect->x = ink_rect->y = + ink_rect->height = ink_rect->width = 0; + if (logical_rect) + logical_rect->x = logical_rect->y = + logical_rect->height = logical_rect->width = 0; + return; + } + + if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) + { + glyph = pango_clutter_get_unknown_glyph (font); + if (glyph == PANGO_GLYPH_EMPTY) + { + /* No unknown glyph found for the font, draw a box */ + PangoFontMetrics *metrics = pango_font_get_metrics (font, NULL); + + if (metrics) + { + if (ink_rect) + { + ink_rect->x = PANGO_SCALE; + ink_rect->width = metrics->approximate_char_width - 2 * PANGO_SCALE; + ink_rect->y = - (metrics->ascent - PANGO_SCALE); + ink_rect->height = metrics->ascent + metrics->descent - 2 * PANGO_SCALE; + } + if (logical_rect) + { + logical_rect->x = 0; + logical_rect->width = metrics->approximate_char_width; + logical_rect->y = -metrics->ascent; + logical_rect->height = metrics->ascent + metrics->descent; + } + + pango_font_metrics_unref (metrics); + } + else + { + if (ink_rect) + ink_rect->x = ink_rect->y = + ink_rect->height = ink_rect->width = 0; + if (logical_rect) + logical_rect->x = logical_rect->y = + logical_rect->height = logical_rect->width = 0; + } + return; + } + } + + info = pango_clutter_font_get_glyph_info (font, glyph, TRUE); + + if (ink_rect) + *ink_rect = info->ink_rect; + if (logical_rect) + *logical_rect = info->logical_rect; +} + +int +pango_clutter_font_get_kerning (PangoFont *font, + PangoGlyph left, + PangoGlyph right) +{ + PangoFcFont *fc_font = PANGO_FC_FONT (font); + + FT_Face face; + FT_Error error; + FT_Vector kerning; + + face = pango_fc_font_lock_face (fc_font); + if (!face) + return 0; + + if (!FT_HAS_KERNING (face)) + { + pango_fc_font_unlock_face (fc_font); + return 0; + } + + error = FT_Get_Kerning (face, left, right, ft_kerning_default, &kerning); + if (error != FT_Err_Ok) + { + pango_fc_font_unlock_face (fc_font); + return 0; + } + + pango_fc_font_unlock_face (fc_font); + return PANGO_UNITS_26_6 (kerning.x); +} + +static FT_Face +pango_clutter_font_real_lock_face (PangoFcFont *font) +{ + return pango_clutter_font_get_face ((PangoFont *)font); +} + +static void +pango_clutter_font_real_unlock_face (PangoFcFont *font) +{ +} + +static gboolean +pango_clutter_free_glyph_info_callback (gpointer key, + gpointer value, + gpointer data) +{ + PangoClutterFont *font = PANGO_CLUTTER_FONT (data); + PangoClutterGlyphInfo *info = value; + + if (font->glyph_cache_destroy && info->cached_glyph) + (*font->glyph_cache_destroy) (info->cached_glyph); + + g_slice_free (PangoClutterGlyphInfo, info); + return TRUE; +} + +static void +pango_clutter_font_finalize (GObject *object) +{ + PangoClutterFont *font = (PangoClutterFont *)object; + + if (font->face) + { + FT_Done_Face (font->face); + font->face = NULL; + } + + g_hash_table_foreach_remove (font->glyph_info, + pango_clutter_free_glyph_info_callback, object); + g_hash_table_destroy (font->glyph_info); + + G_OBJECT_CLASS (pango_clutter_font_parent_class)->finalize (object); +} + +PangoCoverage* +pango_clutter_font_get_coverage (PangoFont *font, PangoLanguage *language) +{ + return pango_font_get_coverage (font, language); +} + +void* +_pango_clutter_font_get_cache_glyph_data (PangoFont *font, int glyph_index) +{ + PangoClutterGlyphInfo *info; + + info = pango_clutter_font_get_glyph_info (font, glyph_index, FALSE); + + return info ? info->cached_glyph : 0; +} + +void +_pango_clutter_font_set_cache_glyph_data (PangoFont *font, + int glyph_index, + void *cached_glyph) +{ + PangoClutterGlyphInfo *info; + + info = pango_clutter_font_get_glyph_info (font, glyph_index, TRUE); + + info->cached_glyph = cached_glyph; +} + +void +_pango_clutter_font_set_glyph_cache_destroy (PangoFont *font, + GDestroyNotify destroy_notify) +{ + PANGO_CLUTTER_FONT (font)->glyph_cache_destroy = destroy_notify; +} diff --git a/clutter/pango/pangoclutter-fontmap.c b/clutter/pango/pangoclutter-fontmap.c new file mode 100644 index 000000000..8531ffd35 --- /dev/null +++ b/clutter/pango/pangoclutter-fontmap.c @@ -0,0 +1,213 @@ +/* Pango + * Clutter fonts handling + * + * Copyright (C) 2000 Red Hat Software + * Copyright (C) 2000 Tor Lillqvist + * Copyright (C) 2006 Marc Lehmann + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#include "pangoclutter.h" +#include "pangoclutter-private.h" + + +#include +#include + +struct _PangoClutterFontMap +{ + PangoFcFontMap parent_instance; + + FT_Library library; + + /* Function to call on prepared patterns to do final + * config tweaking. + */ + PangoClutterSubstituteFunc substitute_func; + gpointer substitute_data; + GDestroyNotify substitute_destroy; + + PangoRenderer *renderer; +}; + +struct _PangoClutterFontMapClass +{ + PangoFcFontMapClass parent_class; +}; + +G_DEFINE_TYPE (PangoClutterFontMap, pango_clutter_font_map, PANGO_TYPE_FC_FONT_MAP) + +static void +pango_clutter_font_map_finalize (GObject *object) +{ + PangoClutterFontMap *fontmap = PANGO_CLUTTER_FONT_MAP (object); + + if (fontmap->renderer) + g_object_unref (fontmap->renderer); + + if (fontmap->substitute_destroy) + fontmap->substitute_destroy (fontmap->substitute_data); + + FT_Done_FreeType (fontmap->library); + + G_OBJECT_CLASS (pango_clutter_font_map_parent_class)->finalize (object); +} + +PangoFontMap * +pango_clutter_font_map_new (void) +{ + PangoClutterFontMap *fontmap; + FT_Error error; + + /* Make sure that the type system is initialized */ + g_type_init (); + + fontmap = g_object_new (PANGO_TYPE_CLUTTER_FONT_MAP, NULL); + + error = FT_Init_FreeType (&fontmap->library); + if (error != FT_Err_Ok) + g_critical ("pango_clutter_font_map_new: Could not initialize freetype"); + + return (PangoFontMap *)fontmap; +} + +void +pango_clutter_font_map_set_default_substitute (PangoClutterFontMap *fontmap, + PangoClutterSubstituteFunc func, + gpointer data, + GDestroyNotify notify) +{ + if (fontmap->substitute_destroy) + fontmap->substitute_destroy (fontmap->substitute_data); + + fontmap->substitute_func = func; + fontmap->substitute_data = data; + fontmap->substitute_destroy = notify; + + pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap)); +} + +/** + * pango_clutter_font_map_substitute_changed: + * @fontmap: a #PangoClutterFontmap + * + * Call this function any time the results of the + * default substitution function set with + * pango_clutter_font_map_set_default_substitute() change. + * That is, if your subsitution function will return different + * results for the same input pattern, you must call this function. + * + * Since: 1.2 + **/ +void +pango_clutter_font_map_substitute_changed (PangoClutterFontMap *fontmap) +{ + pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap)); +} + +/** + * pango_clutter_font_map_create_context: + * @fontmap: a #PangoClutterFontmap + * + * Create a #PangoContext for the given fontmap. + * + * Return value: the newly created context; free with g_object_unref(). + * + * Since: 1.2 + **/ +PangoContext * +pango_clutter_font_map_create_context (PangoClutterFontMap *fontmap) +{ + g_return_val_if_fail (PANGO_CLUTTER_IS_FONT_MAP (fontmap), NULL); + + return pango_fc_font_map_create_context (PANGO_FC_FONT_MAP (fontmap)); +} + +FT_Library +_pango_clutter_font_map_get_library (PangoFontMap *fontmap_) +{ + PangoClutterFontMap *fontmap = (PangoClutterFontMap *)fontmap_; + + return fontmap->library; +} + + +/** + * _pango_clutter_font_map_get_renderer: + * @fontmap: a #PangoClutterFontmap + * + * Gets the singleton PangoClutterRenderer for this fontmap. + * + * Return value: + **/ +PangoRenderer * +_pango_clutter_font_map_get_renderer (PangoClutterFontMap *fontmap) +{ + if (!fontmap->renderer) + fontmap->renderer = g_object_new (PANGO_TYPE_CLUTTER_RENDERER, NULL); + + return fontmap->renderer; +} + +static void +pango_clutter_font_map_default_substitute (PangoFcFontMap *fcfontmap, + FcPattern *pattern) +{ + PangoClutterFontMap *fontmap = PANGO_CLUTTER_FONT_MAP (fcfontmap); + + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + if (fontmap->substitute_func) + fontmap->substitute_func (pattern, fontmap->substitute_data); + +#if 0 + FcValue v; + if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch) + FcPatternAddDouble (pattern, FC_DPI, fontmap->dpi_y); +#endif + FcDefaultSubstitute (pattern); +} + +static PangoFcFont * +pango_clutter_font_map_new_font (PangoFcFontMap *fcfontmap, + FcPattern *pattern) +{ + return (PangoFcFont *)_pango_clutter_font_new (PANGO_CLUTTER_FONT_MAP (fcfontmap), pattern); +} + +static void +pango_clutter_font_map_class_init (PangoClutterFontMapClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + PangoFcFontMapClass *fcfontmap_class = PANGO_FC_FONT_MAP_CLASS (class); + + gobject_class->finalize = pango_clutter_font_map_finalize; + fcfontmap_class->default_substitute = pango_clutter_font_map_default_substitute; + fcfontmap_class->new_font = pango_clutter_font_map_new_font; +} + +static void +pango_clutter_font_map_init (PangoClutterFontMap *fontmap) +{ + fontmap->library = NULL; +} + diff --git a/clutter/pango/pangoclutter-private.h b/clutter/pango/pangoclutter-private.h new file mode 100644 index 000000000..0f049f601 --- /dev/null +++ b/clutter/pango/pangoclutter-private.h @@ -0,0 +1,121 @@ +/* Pango + * pangoclutter-private.h: private symbols for Clutter backend + * + * Copyright (C) 2006 Matthew Allum + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __PANGOCLUTTER_PRIVATE_H__ +#define __PANGOCLUTTER_PRIVATE_H__ + +#include "pangoclutter.h" +#include +#include +#include + +/* Defines duped */ + +#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6)) +#define PANGO_PIXELS_26_6(d) \ + (((d) >= 0) ? \ + ((d) + PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6 : \ + ((d) - PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6) +#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d)) + +#define PANGO_TYPE_CLUTTER_FONT (pango_clutter_font_get_type ()) + +#define PANGO_CLUTTER_FONT(object) \ + (G_TYPE_CHECK_INSTANCE_CAST ((object), \ + PANGO_TYPE_CLUTTER_FONT, \ + PangoClutterFont)) +#define PANGO_CLUTTER_IS_FONT(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CLUTTER_FONT)) + +typedef struct _PangoClutterFont PangoClutterFont; +typedef struct _PangoClutterGlyphInfo PangoClutterGlyphInfo; + +struct _PangoClutterFont +{ + PangoFcFont font; + FT_Face face; + int load_flags; + int size; + GSList *metrics_by_lang; + GHashTable *glyph_info; + GDestroyNotify glyph_cache_destroy; +}; + +struct _PangoClutterGlyphInfo +{ + PangoRectangle logical_rect; + PangoRectangle ink_rect; + void *cached_glyph; +}; + +PangoGlyph +pango_clutter_get_unknown_glyph (PangoFont *font); + +GType pango_clutter_font_get_type (void); + +PangoClutterFont * +_pango_clutter_font_new (PangoClutterFontMap *fontmap, + FcPattern *pattern); +FT_Face +pango_clutter_font_get_face (PangoFont *font); + +FT_Library +_pango_clutter_font_map_get_library (PangoFontMap *fontmap); + +void * +_pango_clutter_font_get_cache_glyph_data (PangoFont *font, + int glyph_index); +void +_pango_clutter_font_set_cache_glyph_data (PangoFont *font, + int glyph_index, + void *cached_glyph); +void +_pango_clutter_font_set_glyph_cache_destroy (PangoFont *font, + GDestroyNotify destroy_notify); + +/* Renderer */ + +typedef struct _PangoClutterRenderer PangoClutterRenderer; + +#define PANGO_TYPE_CLUTTER_RENDERER (pango_clutter_renderer_get_type()) + +#define PANGO_CLUTTER_RENDERER(object) \ + (G_TYPE_CHECK_INSTANCE_CAST ((object), \ + PANGO_TYPE_CLUTTER_RENDERER, \ + PangoClutterRenderer)) + +#define PANGO_IS_CLUTTER_RENDERER(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CLUTTER_RENDERER)) + +GType pango_clutter_renderer_get_type (void); + +PangoRenderer * +_pango_clutter_font_map_get_renderer (PangoClutterFontMap *fontmap); + + +/* HACK make this public to avoid a mass of re-implementation*/ +void +pango_fc_font_get_raw_extents (PangoFcFont *font, + FT_Int32 load_flags, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +#endif diff --git a/clutter/pango/pangoclutter-render.c b/clutter/pango/pangoclutter-render.c new file mode 100644 index 000000000..3bdec3625 --- /dev/null +++ b/clutter/pango/pangoclutter-render.c @@ -0,0 +1,584 @@ +/* Pango + * Rendering routines to Clutter + * + * Copyright (C) 2006 Matthew Allum + * Copyright (C) 2006 Marc Lehmann + * Copyright (C) 2004 Red Hat Software + * Copyright (C) 2000 Tor Lillqvist + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "pangoclutter.h" +#include "pangoclutter-private.h" + +/* + * Texture cache support code + */ + +#define TC_WIDTH 256 +#define TC_HEIGHT 256 +#define TC_ROUND 4 + +typedef struct { + GLuint name; + int x, y, w, h; +} tc_area; + +typedef struct tc_texture { + struct tc_texture *next; + GLuint name; + int avail; +} tc_texture; + +typedef struct tc_slice { + GLuint name; + int avail, y; +} tc_slice; + +static int tc_generation; +static tc_slice slices[TC_HEIGHT / TC_ROUND]; +static tc_texture *first_texture; + +static void +tc_clear () +{ + int i; + + for (i = TC_HEIGHT / TC_ROUND; i--; ) + slices [i].name = 0; + + while (first_texture) + { + tc_texture *next = first_texture->next; + glDeleteTextures (1, &first_texture->name); + g_slice_free (tc_texture, first_texture); + first_texture = next; + } + + printf("freeing textures\n"); + + ++tc_generation; +} + +static void +tc_get (tc_area *area, int width, int height) +{ + int slice_height = MIN (height + TC_ROUND - 1, TC_HEIGHT) & ~(TC_ROUND - 1); + tc_slice *slice = slices + slice_height / TC_ROUND; + + area->w = width; + area->h = height; + + width = MIN (width, TC_WIDTH); + + if (!slice->name || slice->avail < width) + { + /* try to find a texture with enough space */ + tc_texture *tex, *match = 0; + + for (tex = first_texture; tex; tex = tex->next) + if (tex->avail >= slice_height && (!match || match->avail > tex->avail)) + match = tex; + + /* create a new texture if necessary */ + if (!match) + { + CLUTTER_DBG("creating new texture %i x %i\n", TC_WIDTH, TC_HEIGHT); + + match = g_slice_new (tc_texture); + match->next = first_texture; + first_texture = match; + glGenTextures (1, &match->name); + match->avail = TC_HEIGHT; + + glBindTexture (GL_TEXTURE_2D, match->name); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, + TC_WIDTH, TC_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); + } + + match->avail -= slice_height; + + slice->name = match->name; + slice->avail = TC_WIDTH; + slice->y = match->avail; + } + + slice->avail -= width; + + area->name = slice->name; + area->x = slice->avail; + area->y = slice->y; +} + +static void +tc_put (tc_area *area) +{ + /* our management is too primitive to support this operation yet */ +} + +/*******************/ + + +#define PANGO_CLUTTER_RENDERER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + PANGO_TYPE_CLUTTER_RENDERER, \ + PangoClutterRendererClass)) + +#define PANGO_IS_CLUTTER_RENDERER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_CLUTTER_RENDERER)) + +#define PANGO_CLUTTER_RENDERER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + PANGO_TYPE_CLUTTER_RENDERER, \ + PangoClutterRendererClass)) + +typedef struct { + PangoRendererClass parent_class; +} PangoClutterRendererClass; + +struct _PangoClutterRenderer +{ + PangoRenderer parent_instance; + ClutterColor color; + int flags; + GLuint curtex; /* current texture */ +}; + +G_DEFINE_TYPE (PangoClutterRenderer, \ + pango_clutter_renderer, \ + PANGO_TYPE_RENDERER) + +typedef struct +{ + guint8 *bitmap; + int width, stride, height, top, left; +} Glyph; + +static void * +temp_buffer (size_t size) +{ + static char *buffer; + static size_t alloc; + + if (size > alloc) + { + size = (size + 4095) & ~4095; + free (buffer); + alloc = size; + buffer = malloc (size); + } + + return buffer; +} + +static void +render_box (Glyph *glyph, int width, int height, int top) +{ + int i; + int left = 0; + + if (height > 2) + { + height -= 2; + top++; + } + + if (width > 2) + { + width -= 2; + left++; + } + + glyph->stride = (width + 3) & ~3; + glyph->width = width; + glyph->height = height; + glyph->top = top; + glyph->left = left; + + glyph->bitmap = temp_buffer (width * height); + memset (glyph->bitmap, 0, glyph->stride * height); + + for (i = width; i--; ) + glyph->bitmap [i] + = glyph->bitmap [i + (height - 1) * glyph->stride] = 0xff; + + for (i = height; i--; ) + glyph->bitmap [i * glyph->stride] + = glyph->bitmap [i * glyph->stride + (width - 1)] = 0xff; +} + +static void +font_render_glyph (Glyph *glyph, PangoFont *font, int glyph_index) +{ + FT_Face face; + + if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG) + { + PangoFontMetrics *metrics; + + if (!font) + goto generic_box; + + metrics = pango_font_get_metrics (font, NULL); + if (!metrics) + goto generic_box; + + render_box (glyph, PANGO_PIXELS (metrics->approximate_char_width), + PANGO_PIXELS (metrics->ascent + metrics->descent), + PANGO_PIXELS (metrics->ascent)); + + pango_font_metrics_unref (metrics); + + return; + } + + face = pango_clutter_font_get_face (font); + + if (face) + { + PangoClutterFont *glfont = (PangoClutterFont *)font; + + FT_Load_Glyph (face, glyph_index, glfont->load_flags); + FT_Render_Glyph (face->glyph, ft_render_mode_normal); + + glyph->width = face->glyph->bitmap.width; + glyph->stride = face->glyph->bitmap.pitch; + glyph->height = face->glyph->bitmap.rows; + glyph->top = face->glyph->bitmap_top; + glyph->left = face->glyph->bitmap_left; + glyph->bitmap = face->glyph->bitmap.buffer; + } + else + generic_box: + render_box (glyph, PANGO_UNKNOWN_GLYPH_WIDTH, + PANGO_UNKNOWN_GLYPH_HEIGHT, PANGO_UNKNOWN_GLYPH_HEIGHT); +} + +typedef struct glyph_info +{ + tc_area tex; + int left, top; + int generation; +} +glyph_info; + +static void +free_glyph_info (glyph_info *g) +{ + tc_put (&g->tex); + g_slice_free (glyph_info, g); +} + +static void +draw_glyph (PangoRenderer *renderer_, + PangoFont *font, + PangoGlyph glyph, + double x, + double y) +{ + PangoClutterRenderer *renderer = PANGO_CLUTTER_RENDERER (renderer_); + glyph_info *g; + float x1, y1, x2, y2; + + if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) + { + glyph = pango_clutter_get_unknown_glyph (font); + + if (glyph == PANGO_GLYPH_EMPTY) + glyph = PANGO_GLYPH_UNKNOWN_FLAG; + } + + g = _pango_clutter_font_get_cache_glyph_data (font, glyph); + + if (!g || g->generation != tc_generation) + { + Glyph bm; + font_render_glyph (&bm, font, glyph); + + if (g) + g->generation = tc_generation; + else + { + g = g_slice_new (glyph_info); + + _pango_clutter_font_set_glyph_cache_destroy + (font, (GDestroyNotify)free_glyph_info); + _pango_clutter_font_set_cache_glyph_data (font, glyph, g); + } + + if (renderer->curtex) + glEnd (); + + tc_get (&g->tex, bm.width, bm.height); + + g->left = bm.left; + g->top = bm.top; + + CLUTTER_DBG("cache fail; subimage2d %i\n", glyph); + + glBindTexture (GL_TEXTURE_2D, g->tex.name); + glPixelStorei (GL_UNPACK_ROW_LENGTH, bm.stride); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + glTexSubImage2D (GL_TEXTURE_2D, + 0, + g->tex.x, + g->tex.y, + bm.width, + bm.height, + GL_ALPHA, + GL_UNSIGNED_BYTE, + bm.bitmap); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei (GL_UNPACK_ALIGNMENT, 4); + + renderer->curtex = g->tex.name; + glBegin (GL_QUADS); + } + else CLUTTER_DBG("cache succsess %i\n", glyph); + + x += g->left; + y -= g->top; + + x1 = g->tex.x * (1. / TC_WIDTH ); + y1 = g->tex.y * (1. / TC_HEIGHT); + x2 = g->tex.w * (1. / TC_WIDTH ) + x1; + y2 = g->tex.h * (1. / TC_HEIGHT) + y1; + + if (g->tex.name != renderer->curtex) + { + if (renderer->curtex) + glEnd (); + + glBindTexture (GL_TEXTURE_2D, g->tex.name); + renderer->curtex = g->tex.name; + + glBegin (GL_QUADS); + } + + glTexCoord2f (x1, y1); glVertex2i (x , y ); + glTexCoord2f (x2, y1); glVertex2i (x + g->tex.w, y ); + glTexCoord2f (x2, y2); glVertex2i (x + g->tex.w, y + g->tex.h); + glTexCoord2f (x1, y2); glVertex2i (x , y + g->tex.h); +} + +static void +draw_trapezoid (PangoRenderer *renderer_, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22) +{ + PangoClutterRenderer *renderer = (PangoClutterRenderer *)renderer_; + + if (renderer->curtex) + { + glEnd (); + renderer->curtex = 0; + } + + glDisable (GL_TEXTURE_2D); + + glBegin (GL_QUADS); + glVertex2d (x11, y1); + glVertex2d (x21, y1); + glVertex2d (x22, y2); + glVertex2d (x12, y2); + glEnd (); + + glEnable (GL_TEXTURE_2D); +} + +void +pango_clutter_render_layout_subpixel (PangoLayout *layout, + int x, + int y, + ClutterColor *color, + int flags) +{ + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; + + context = pango_layout_get_context (layout); + fontmap = pango_context_get_font_map (context); + renderer = _pango_clutter_font_map_get_renderer + (PANGO_CLUTTER_FONT_MAP (fontmap)); + + memcpy (&(PANGO_CLUTTER_RENDERER (renderer)->color), + color, sizeof(ClutterColor)); + + pango_renderer_draw_layout (renderer, layout, x, y); +} + +void +pango_clutter_render_layout (PangoLayout *layout, + int x, + int y, + ClutterColor *color, + int flags) +{ + pango_clutter_render_layout_subpixel (layout, + x * PANGO_SCALE, + y * PANGO_SCALE, + color, + flags); +} + +void +pango_clutter_render_layout_line (PangoLayoutLine *line, + int x, + int y, + ClutterColor *color) +{ + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; + + context = pango_layout_get_context (line->layout); + fontmap = pango_context_get_font_map (context); + renderer = _pango_clutter_font_map_get_renderer + (PANGO_CLUTTER_FONT_MAP (fontmap)); + + memcpy (&(PANGO_CLUTTER_RENDERER (renderer)->color), + color, sizeof(ClutterColor)); + + pango_renderer_draw_layout_line (renderer, line, x, y); +} + +void +pango_clutter_render_clear_caches (void) +{ + tc_clear(); +} + +static void +pango_clutter_renderer_init (PangoClutterRenderer *renderer) +{ + memset (&renderer->color, 0xff, sizeof(ClutterColor)); +} + +static void +prepare_run (PangoRenderer *renderer, PangoLayoutRun *run) +{ + PangoClutterRenderer *glrenderer = (PangoClutterRenderer *)renderer; + PangoColor *fg = 0; + GSList *l; + unsigned char r, g, b, a; + + renderer->underline = PANGO_UNDERLINE_NONE; + renderer->strikethrough = FALSE; + + for (l = run->item->analysis.extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + switch (attr->klass->type) + { + case PANGO_ATTR_UNDERLINE: + renderer->underline = ((PangoAttrInt *)attr)->value; + break; + + case PANGO_ATTR_STRIKETHROUGH: + renderer->strikethrough = ((PangoAttrInt *)attr)->value; + break; + + case PANGO_ATTR_FOREGROUND: + fg = &((PangoAttrColor *)attr)->color; + break; + default: + break; + } + } + + if (fg) + { + r = fg->red * (255.f / 65535.f); + g = fg->green * (255.f / 65535.f); + b = fg->blue * (255.f / 65535.f); + } + else + { + r = glrenderer->color.red; + g = glrenderer->color.green; + b = glrenderer->color.blue; + } + + a = glrenderer->color.alpha; + + if (glrenderer->flags & FLAG_INVERSE) + { + r ^= 0xffU; + g ^= 0xffU; + b ^= 0xffU; + } + + glColor4ub (r, g, b, a); +} + +static void +draw_begin (PangoRenderer *renderer_) +{ + PangoClutterRenderer *renderer = (PangoClutterRenderer *)renderer_; + + renderer->curtex = 0; + + glEnable (GL_TEXTURE_2D); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable (GL_BLEND); +#if 0 + gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE , GL_ONE_MINUS_SRC_ALPHA); +#endif + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#if 0 + glEnable (GL_ALPHA_TEST); + glAlphaFunc (GL_GREATER, 0.01f); +#endif +} + +static void +draw_end (PangoRenderer *renderer_) +{ + PangoClutterRenderer *renderer = (PangoClutterRenderer *)renderer_; + + if (renderer->curtex) + glEnd (); + + glDisable (GL_ALPHA_TEST); + glDisable (GL_BLEND); + glDisable (GL_TEXTURE_2D); +} + +static void +pango_clutter_renderer_class_init (PangoClutterRendererClass *klass) +{ + PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); + + renderer_class->draw_glyph = draw_glyph; + renderer_class->draw_trapezoid = draw_trapezoid; + renderer_class->prepare_run = prepare_run; + renderer_class->begin = draw_begin; + renderer_class->end = draw_end; +} + diff --git a/clutter/pango/pangoclutter.h b/clutter/pango/pangoclutter.h new file mode 100644 index 000000000..9f58c9274 --- /dev/null +++ b/clutter/pango/pangoclutter.h @@ -0,0 +1,97 @@ +/* Pango + * pangoclutter.h: Clutter/Freetype2 backend + * + * Copyright (C) 1999 Red Hat Software + * Copyright (C) 2000 Tor Lillqvist + * Copyright (C) 2006 Marc Lehmann + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef PANGOCLUTTER_H__ +#define PANGOCLUTTER_H__ + +#define PANGO_ENABLE_BACKEND +#define G_DISABLE_CAST_CHECKS + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define PANGO_TYPE_CLUTTER_FONT_MAP \ + (pango_clutter_font_map_get_type ()) + +#define PANGO_CLUTTER_FONT_MAP(object) \ + (G_TYPE_CHECK_INSTANCE_CAST ((object), \ + PANGO_TYPE_CLUTTER_FONT_MAP, \ + PangoClutterFontMap)) + +#define PANGO_CLUTTER_IS_FONT_MAP(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CLUTTER_FONT_MAP)) + +typedef struct _PangoClutterFontMap PangoClutterFontMap; +typedef struct _PangoClutterFontMapClass PangoClutterFontMapClass; + +typedef void (*PangoClutterSubstituteFunc) (FcPattern *pattern, gpointer data); + +GType pango_clutter_font_map_get_type (void); + +PangoFontMap* +pango_clutter_font_map_new (void); + +void +pango_clutter_font_map_set_default_substitute + (PangoClutterFontMap *fontmap, + PangoClutterSubstituteFunc func, + gpointer data, + GDestroyNotify notify); + +void +pango_clutter_font_map_substitute_changed (PangoClutterFontMap *fontmap); + +PangoContext * +pango_clutter_font_map_create_context (PangoClutterFontMap *fontmap); + +#define FLAG_INVERSE 1 +#define FLAG_OUTLINE 2 // not yet implemented + +void +pango_clutter_render_layout_subpixel (PangoLayout *layout, + int x, + int y, + ClutterColor *color, + int flags); +void +pango_clutter_render_layout (PangoLayout *layout, + int x, + int y, + ClutterColor *color, + int flags); + +void +pango_clutter_render_layout_line (PangoLayoutLine *line, + int x, + int y, + ClutterColor *color); + +void +pango_clutter_render_clear_caches (); + +G_END_DECLS + +#endif diff --git a/configure.ac b/configure.ac index 583164d5c..27e157d3c 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,7 @@ AC_SUBST(CLUTTER_CFLAGS) AC_SUBST(CLUTTER_LIBS) AC_OUTPUT([Makefile +clutter/pango/Makefile clutter/Makefile gtk/Makefile gtk/gtk-clutter.pc diff --git a/examples/super-oh.c b/examples/super-oh.c index 2b17b8a90..dfc206e42 100644 --- a/examples/super-oh.c +++ b/examples/super-oh.c @@ -186,10 +186,10 @@ main (int argc, char *argv[]) clutter_group_add (CLUTTER_GROUP (oh->group), oh->hand[i]); } - clutter_actor_set_scale (oh->group, .1, 0.1); - #if 0 { + clutter_actor_set_scale (oh->group, .1, 0.1); + guint w, h; clutter_actor_get_abs_size (CLUTTER_ACTOR(oh->hand[0]), &w, &h); g_print ("%ix%i\n", w, h); diff --git a/examples/test.c b/examples/test.c index 30c24972d..4c44705eb 100644 --- a/examples/test.c +++ b/examples/test.c @@ -43,7 +43,10 @@ text_cb (ClutterTimeline *timeline, g_snprintf(buf, 32, "--> %i <--", frame_num); clutter_label_set_text (label, buf); - // clutter_actor_set_opacity (CLUTTER_ACTOR(label), opacity); + clutter_actor_set_size(CLUTTER_ACTOR(label), 150, 0); + clutter_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); + + clutter_actor_set_opacity (CLUTTER_ACTOR(label), opacity); clutter_actor_rotate_z (CLUTTER_ACTOR(label), frame_num, @@ -66,7 +69,7 @@ main (int argc, char *argv[]) ClutterActor *texture, *label, *rect, *para; ClutterActor *stage; ClutterTimeline *timeline; - ClutterColor rect_col = { 0xff, 0x0, 0x0, 0xff }; + ClutterColor rect_col = { 0xff, 0x0, 0x0, 0x99 }; GdkPixbuf *pixbuf; clutter_init (&argc, &argv); @@ -87,6 +90,8 @@ main (int argc, char *argv[]) clutter_actor_set_opacity (CLUTTER_ACTOR(label), 0x99); clutter_actor_set_position (CLUTTER_ACTOR(label), 550, 100); + clutter_actor_set_size(label, 400, 0); + rect = clutter_rectangle_new_with_color(&rect_col); clutter_actor_set_size(rect, 100, 100); @@ -94,7 +99,7 @@ main (int argc, char *argv[]) para = clutter_label_new_with_text ("Sans 24", PARA_TEXT); clutter_actor_set_position(para, 10, 10); - clutter_label_set_text_extents (CLUTTER_LABEL(para), 200, 0); + clutter_actor_set_size(para, 200, 0); clutter_group_add (CLUTTER_GROUP (stage), texture); clutter_group_add (CLUTTER_GROUP (stage), label);