X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fgdkpango.c;h=ca5745beb27f012eb1d47b549f3e367d59df4c12;hb=3eef3290ad42fa7b615cfbca37551de490de71ef;hp=2a6b1ead5d8d77bf71a55423120ea8aa274992d4;hpb=300e6b84cd0c36873005dd877e3039870d43741b;p=~andy%2Fgtk diff --git a/gdk/gdkpango.c b/gdk/gdkpango.c index 2a6b1ead5..ca5745beb 100644 --- a/gdk/gdkpango.c +++ b/gdk/gdkpango.c @@ -12,1228 +12,117 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" -#include -#include -#include "gdkcairo.h" -#include "gdkcolor.h" -#include "gdkgc.h" -#include "gdkinternals.h" + #include "gdkpango.h" -#include "gdkrgb.h" -#include "gdkprivate.h" + #include "gdkscreen.h" #include "gdkintl.h" -#include "gdkalias.h" - -#define GDK_INFO_KEY "gdk-info" - -/* We have various arrays indexed by render part; if PangoRenderPart - * is extended, we want to make sure not to overwrite the end of - * those arrays. - */ -#define MAX_RENDER_PART PANGO_RENDER_PART_STRIKETHROUGH - -struct _GdkPangoRendererPrivate -{ - GdkScreen *screen; - - /* GdkPangoRenderer specific state */ - PangoColor override_color[MAX_RENDER_PART + 1]; - gboolean override_color_set[MAX_RENDER_PART + 1]; - - GdkBitmap *stipple[MAX_RENDER_PART + 1]; - PangoColor emboss_color; - gboolean embossed; - - cairo_t *cr; - PangoRenderPart last_part; - - /* Current target */ - GdkDrawable *drawable; - GdkGC *base_gc; - - gboolean gc_changed; -}; - -static PangoAttrType gdk_pango_attr_stipple_type; -static PangoAttrType gdk_pango_attr_embossed_type; -static PangoAttrType gdk_pango_attr_emboss_color_type; - -enum { - PROP_0, - PROP_SCREEN -}; - -G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER) - -static void -gdk_pango_renderer_finalize (GObject *object) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - int i; - - if (priv->base_gc) - g_object_unref (priv->base_gc); - if (priv->drawable) - g_object_unref (priv->drawable); - - for (i = 0; i <= MAX_RENDER_PART; i++) - if (priv->stipple[i]) - g_object_unref (priv->stipple[i]); - - G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object); -} - -static GObject* -gdk_pango_renderer_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) -{ - GObject *object; - GdkPangoRenderer *gdk_renderer; - - object = G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor (type, - n_construct_properties, - construct_params); - - gdk_renderer = GDK_PANGO_RENDERER (object); - - if (!gdk_renderer->priv->screen) - { - g_warning ("Screen must be specified at construct time for GdkPangoRenderer"); - gdk_renderer->priv->screen = gdk_screen_get_default (); - } - - return object; -} - -/* Adjusts matrix and color for the renderer to draw the secondary - * "shadow" copy for embossed text */ -static void -emboss_context (GdkPangoRenderer *renderer, cairo_t *cr) -{ - GdkPangoRendererPrivate *priv = renderer->priv; - cairo_matrix_t tmp_matrix; - double red, green, blue; - - /* The gymnastics here to adjust the matrix are because we want - * to offset by +1,+1 in device-space, not in user-space, - * so we can't just draw the layout at x + 1, y + 1 - */ - cairo_get_matrix (cr, &tmp_matrix); - tmp_matrix.x0 += 1.0; - tmp_matrix.y0 += 1.0; - cairo_set_matrix (cr, &tmp_matrix); - - red = (double) priv->emboss_color.red / 65535.; - green = (double) priv->emboss_color.green / 65535.; - blue = (double) priv->emboss_color.blue / 65535.; - - cairo_set_source_rgb (cr, red, green, blue); -} - -static inline gboolean -color_equal (const PangoColor *c1, const PangoColor *c2) -{ - if (!c1 && !c2) - return TRUE; - - if (c1 && c2 && - c1->red == c2->red && - c1->green == c2->green && - c1->blue == c2->blue) - return TRUE; - - return FALSE; -} - -static cairo_t * -get_cairo_context (GdkPangoRenderer *gdk_renderer, - PangoRenderPart part) -{ - PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - - if (!priv->cr) - { - const PangoMatrix *matrix; - - priv->cr = gdk_cairo_create (priv->drawable); - - matrix = pango_renderer_get_matrix (renderer); - if (matrix) - { - cairo_matrix_t cairo_matrix; - - cairo_matrix_init (&cairo_matrix, - matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - matrix->x0, matrix->y0); - cairo_set_matrix (priv->cr, &cairo_matrix); - } - } - - if (part != priv->last_part) - { - PangoColor *pango_color; - GdkColor *color; - GdkColor tmp_color; - gboolean changed; - - pango_color = pango_renderer_get_color (renderer, part); - - if (priv->last_part != -1) - changed = priv->gc_changed || - priv->stipple[priv->last_part] != priv->stipple[part] || - !color_equal (pango_color, - pango_renderer_get_color (renderer, priv->last_part)); - else - changed = TRUE; - - if (changed) - { - if (pango_color) - { - tmp_color.red = pango_color->red; - tmp_color.green = pango_color->green; - tmp_color.blue = pango_color->blue; - - color = &tmp_color; - } - else - color = NULL; - - _gdk_gc_update_context (priv->base_gc, - priv->cr, - color, - priv->stipple[part], - priv->gc_changed, - priv->drawable); - } - - priv->last_part = part; - priv->gc_changed = FALSE; - } - - return priv->cr; -} - -static void -gdk_pango_renderer_draw_glyphs (PangoRenderer *renderer, - PangoFont *font, - PangoGlyphString *glyphs, - int x, - int y) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - cairo_t *cr; - - cr = get_cairo_context (gdk_renderer, - PANGO_RENDER_PART_FOREGROUND); - - if (priv->embossed) - { - cairo_save (cr); - emboss_context (gdk_renderer, cr); - cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE); - pango_cairo_show_glyph_string (cr, font, glyphs); - cairo_restore (cr); - } - - cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE); - pango_cairo_show_glyph_string (cr, font, glyphs); -} - -static void -gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer, - PangoRenderPart part, - int x, - int y, - int width, - int height) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - cairo_t *cr; - - cr = get_cairo_context (gdk_renderer, part); - - if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND) - { - cairo_save (cr); - emboss_context (gdk_renderer, cr); - cairo_rectangle (cr, - (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, - (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); - - cairo_fill (cr); - cairo_restore (cr); - } - - cairo_rectangle (cr, - (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, - (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); - cairo_fill (cr); -} - -static void -gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer, - int x, - int y, - int width, - int height) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - cairo_t *cr; - - cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE); - - if (priv->embossed) - { - cairo_save (cr); - emboss_context (gdk_renderer, cr); - pango_cairo_show_error_underline (cr, - (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, - (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); - cairo_restore (cr); - } - - pango_cairo_show_error_underline (cr, - (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, - (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); -} - -static void -gdk_pango_renderer_draw_shape (PangoRenderer *renderer, - PangoAttrShape *attr, - int x, - int y) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - PangoLayout *layout; - PangoCairoShapeRendererFunc shape_renderer; - gpointer shape_renderer_data; - cairo_t *cr; - double dx = (double)x / PANGO_SCALE, dy = (double)y / PANGO_SCALE; - - layout = pango_renderer_get_layout (renderer); - - if (!layout) - return; - - shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout), - &shape_renderer_data); - - if (!shape_renderer) - return; - - cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_FOREGROUND); - - cairo_save (cr); - - if (priv->embossed) - { - cairo_save (cr); - emboss_context (gdk_renderer, cr); - cairo_move_to (cr, dx, dy); - shape_renderer (cr, attr, FALSE, shape_renderer_data); - - cairo_restore (cr); - } - - cairo_move_to (cr, dx, dy); - shape_renderer (cr, attr, FALSE, shape_renderer_data); - - cairo_restore (cr); -} - -static void -gdk_pango_renderer_part_changed (PangoRenderer *renderer, - PangoRenderPart part) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - - if (gdk_renderer->priv->last_part == part) - gdk_renderer->priv->last_part = (PangoRenderPart)-1; -} - -static void -gdk_pango_renderer_begin (PangoRenderer *renderer) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - - if (!priv->drawable || !priv->base_gc) - { - g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()" - "must be used to set the target drawable and GC before using the renderer\n"); - } -} - -static void -gdk_pango_renderer_end (PangoRenderer *renderer) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - GdkPangoRendererPrivate *priv = gdk_renderer->priv; - - if (priv->cr) - { - cairo_destroy (priv->cr); - priv->cr = NULL; - } - priv->last_part = (PangoRenderPart)-1; -} - -static void -gdk_pango_renderer_prepare_run (PangoRenderer *renderer, - PangoLayoutRun *run) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - gboolean embossed = FALSE; - GdkBitmap *stipple = NULL; - gboolean changed = FALSE; - PangoColor emboss_color; - GSList *l; - int i; - - emboss_color.red = 0xffff; - emboss_color.green = 0xffff; - emboss_color.blue = 0xffff; - - for (l = run->item->analysis.extra_attrs; l; l = l->next) - { - PangoAttribute *attr = l->data; - - /* stipple_type and embossed_type aren't necessarily - * initialized, but they are 0, which is an - * invalid type so won't occur. - */ - if (attr->klass->type == gdk_pango_attr_stipple_type) - { - stipple = ((GdkPangoAttrStipple*)attr)->stipple; - } - else if (attr->klass->type == gdk_pango_attr_embossed_type) - { - embossed = ((GdkPangoAttrEmbossed*)attr)->embossed; - } - else if (attr->klass->type == gdk_pango_attr_emboss_color_type) - { - emboss_color = ((GdkPangoAttrEmbossColor*)attr)->color; - } - } - - gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple); - gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple); - gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple); - gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple); - - if (embossed != gdk_renderer->priv->embossed) - { - gdk_renderer->priv->embossed = embossed; - changed = TRUE; - } - - if (!color_equal (&gdk_renderer->priv->emboss_color, &emboss_color)) - { - gdk_renderer->priv->emboss_color = emboss_color; - changed = TRUE; - } - - if (changed) - pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND); - - PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run); - - for (i = 0; i <= MAX_RENDER_PART; i++) - { - if (gdk_renderer->priv->override_color_set[i]) - pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]); - } -} - -static void -gdk_pango_renderer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object); - - switch (prop_id) - { - case PROP_SCREEN: - gdk_renderer->priv->screen = g_value_get_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdk_pango_renderer_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object); - - switch (prop_id) - { - case PROP_SCREEN: - g_value_set_object (value, gdk_renderer->priv->screen); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdk_pango_renderer_init (GdkPangoRenderer *renderer) -{ - renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, - GDK_TYPE_PANGO_RENDERER, - GdkPangoRendererPrivate); - - renderer->priv->last_part = (PangoRenderPart)-1; - renderer->priv->gc_changed = TRUE; -} - -static void -gdk_pango_renderer_class_init (GdkPangoRendererClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); - - renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs; - renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle; - renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline; - renderer_class->draw_shape = gdk_pango_renderer_draw_shape; - renderer_class->part_changed = gdk_pango_renderer_part_changed; - renderer_class->begin = gdk_pango_renderer_begin; - renderer_class->end = gdk_pango_renderer_end; - renderer_class->prepare_run = gdk_pango_renderer_prepare_run; - - object_class->finalize = gdk_pango_renderer_finalize; - object_class->constructor = gdk_pango_renderer_constructor; - object_class->set_property = gdk_pango_renderer_set_property; - object_class->get_property = gdk_pango_renderer_get_property; - - g_object_class_install_property (object_class, - PROP_SCREEN, - g_param_spec_object ("screen", - P_("Screen"), - P_("the GdkScreen for the renderer"), - GDK_TYPE_SCREEN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); - - g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate)); -} - -/** - * gdk_pango_renderer_new: - * @screen: a #GdkScreen - * - * Creates a new #PangoRenderer for @screen. Normally you can use the - * results of gdk_pango_renderer_get_default() rather than creating a new - * renderer. - * - * Return value: a newly created #PangoRenderer. Free with g_object_unref(). - * - * Since: 2.6 - **/ -PangoRenderer * -gdk_pango_renderer_new (GdkScreen *screen) -{ - g_return_val_if_fail (screen != NULL, NULL); - - return g_object_new (GDK_TYPE_PANGO_RENDERER, - "screen", screen, - NULL); -} - -static void -on_renderer_display_closed (GdkDisplay *display, - gboolean is_error, - GdkPangoRenderer *renderer) -{ - g_signal_handlers_disconnect_by_func (display, - on_renderer_display_closed, - renderer); - g_object_set_data (G_OBJECT (renderer->priv->screen), - g_intern_static_string ("gdk-pango-renderer"), NULL); -} - -/** - * gdk_pango_renderer_get_default: - * @screen: a #GdkScreen - * - * Gets the default #PangoRenderer for a screen. This default renderer - * is shared by all users of the display, so properties such as the color - * or transformation matrix set for the renderer may be overwritten - * by functions such as gdk_draw_layout(). - * - * Before using the renderer, you need to call gdk_pango_renderer_set_drawable() - * and gdk_pango_renderer_set_gc() to set the drawable and graphics context - * to use for drawing. - * - * Return value: the default #PangoRenderer for @screen. The - * renderer is owned by GTK+ and will be kept around until the - * screen is closed. - * - * Since: 2.6 - **/ -PangoRenderer * -gdk_pango_renderer_get_default (GdkScreen *screen) -{ - PangoRenderer *renderer; - - g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); - - renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer"); - if (!renderer) - { - renderer = gdk_pango_renderer_new (screen); - g_object_set_data_full (G_OBJECT (screen), - g_intern_static_string ("gdk-pango-renderer"), renderer, - (GDestroyNotify)g_object_unref); - - g_signal_connect (gdk_screen_get_display (screen), "closed", - G_CALLBACK (on_renderer_display_closed), renderer); - } - - return renderer; -} - -/** - * gdk_pango_renderer_set_drawable: - * @gdk_renderer: a #GdkPangoRenderer - * @drawable: (allow-none): the new target drawable, or %NULL - * - * Sets the drawable the renderer draws to. - * - * Since: 2.6 - **/ -void -gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer, - GdkDrawable *drawable) -{ - GdkPangoRendererPrivate *priv; - - g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer)); - g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable)); - - priv = gdk_renderer->priv; - - if (priv->drawable != drawable) - { - if (priv->drawable) - g_object_unref (priv->drawable); - priv->drawable = drawable; - if (priv->drawable) - g_object_ref (priv->drawable); - } -} - -/** - * gdk_pango_renderer_set_gc: - * @gdk_renderer: a #GdkPangoRenderer - * @gc: (allow-none): the new GC to use for drawing, or %NULL - * - * Sets the GC the renderer draws with. Note that the GC must not be - * modified until it is unset by calling the function again with - * %NULL for the @gc parameter, since GDK may make internal copies - * of the GC which won't be updated to follow changes to the - * original GC. - * - * Since: 2.6 - **/ -void -gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer, - GdkGC *gc) -{ - GdkPangoRendererPrivate *priv; - - g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer)); - g_return_if_fail (gc == NULL || GDK_IS_GC (gc)); - - priv = gdk_renderer->priv; - - if (priv->base_gc != gc) - { - if (priv->base_gc) - g_object_unref (priv->base_gc); - priv->base_gc = gc; - if (priv->base_gc) - g_object_ref (priv->base_gc); - - priv->gc_changed = TRUE; - } -} +#include +#include /** - * gdk_pango_renderer_set_stipple: - * @gdk_renderer: a #GdkPangoRenderer - * @part: the part to render with the stipple - * @stipple: the new stipple value. - * - * Sets the stipple for one render part (foreground, background, underline, - * etc.) Note that this is overwritten when iterating through the individual - * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus - * only useful when you call low level functions like pango_renderer_draw_glyphs() - * directly, or in the 'prepare_run' virtual function of a subclass of - * #GdkPangoRenderer. + * SECTION:pango_interaction + * @Short_description: Using Pango in GDK + * @Title: Pango Interaction * - * Since: 2.6 - **/ -void -gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer, - PangoRenderPart part, - GdkBitmap *stipple) -{ - g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer)); - - if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */ - return; - - if (stipple != gdk_renderer->priv->stipple[part]) - { - if (gdk_renderer->priv->stipple[part]) - g_object_unref (gdk_renderer->priv->stipple[part]); - - gdk_renderer->priv->stipple[part] = stipple; - - if (gdk_renderer->priv->stipple[part]) - g_object_ref (gdk_renderer->priv->stipple[part]); - - pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part); - } -} - -/** - * gdk_pango_renderer_set_override_color: - * @gdk_renderer: a #GdkPangoRenderer - * @part: the part to render to set the color of - * @color: (allow-none): the color to use, or %NULL to unset a previously - * set override color. - * - * Sets the color for a particular render part (foreground, - * background, underline, etc.), overriding any attributes on the layouts - * renderered with this renderer. - * - * Since: 2.6 - **/ -void -gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer, - PangoRenderPart part, - const GdkColor *color) -{ - GdkPangoRendererPrivate *priv; - - g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer)); - - priv = gdk_renderer->priv; - - if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */ - return; - - if (color) - { - priv->override_color[part].red = color->red; - priv->override_color[part].green = color->green; - priv->override_color[part].blue = color->blue; - priv->override_color_set[part] = TRUE; - } - else - priv->override_color_set[part] = FALSE; -} - -/* Gets a renderer to draw with, setting the properties of the - * renderer and activating it. Note that since we activate the - * renderer here, the implicit setting of the matrix that - * pango_renderer_draw_layout_[line] normally do when they - * activate the renderer is suppressed. */ -static PangoRenderer * -get_renderer (GdkDrawable *drawable, - GdkGC *gc, - const GdkColor *foreground, - const GdkColor *background) -{ - GdkScreen *screen = gdk_drawable_get_screen (drawable); - PangoRenderer *renderer = gdk_pango_renderer_get_default (screen); - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - - gdk_pango_renderer_set_drawable (gdk_renderer, drawable); - gdk_pango_renderer_set_gc (gdk_renderer, gc); - - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_FOREGROUND, - foreground); - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_UNDERLINE, - foreground); - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_STRIKETHROUGH, - foreground); - - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_BACKGROUND, - background); - - pango_renderer_activate (renderer); - - return renderer; -} - -/* Cleans up the renderer obtained with get_renderer() */ -static void -release_renderer (PangoRenderer *renderer) -{ - GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer); - - pango_renderer_deactivate (renderer); - - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_FOREGROUND, - NULL); - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_UNDERLINE, - NULL); - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_STRIKETHROUGH, - NULL); - gdk_pango_renderer_set_override_color (gdk_renderer, - PANGO_RENDER_PART_BACKGROUND, - NULL); - - gdk_pango_renderer_set_drawable (gdk_renderer, NULL); - gdk_pango_renderer_set_gc (gdk_renderer, NULL); -} - -/** - * gdk_draw_layout_line_with_colors: - * @drawable: the drawable on which to draw the line - * @gc: base graphics to use - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * @line: a #PangoLayoutLine - * @foreground: (allow-none): foreground override color, or %NULL for none - * @background: (allow-none): background override color, or %NULL for none + * Pango is the text layout system used by GDK and GTK+. The functions + * and types in this section are used to obtain clip regions for + * #PangoLayouts, and to get #PangoContexts that can be used with + * GDK. * - * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the - * layout's normal colors with @foreground and/or @background. - * @foreground and @background need not be allocated. + * Creating a #PangoLayout object is the first step in rendering text, + * and requires getting a handle to a #PangoContext. For GTK+ programs, + * you'll usually want to use gtk_widget_get_pango_context(), or + * gtk_widget_create_pango_layout(), rather than using the lowlevel + * gdk_pango_context_get_for_screen(). Once you have a #PangoLayout, you + * can set the text and attributes of it with Pango functions like + * pango_layout_set_text() and get its size with pango_layout_get_size(). + * (Note that Pango uses a fixed point system internally, so converting + * between Pango units and pixels using PANGO_SCALE or the PANGO_PIXELS() macro.) * - * If the layout's #PangoContext has a transformation matrix set, then - * @x and @y specify the position of the left edge of the baseline - * (left is in before-tranform user coordinates) in after-transform - * device coordinates. - */ -void -gdk_draw_layout_line_with_colors (GdkDrawable *drawable, - GdkGC *gc, - gint x, - gint y, - PangoLayoutLine *line, - const GdkColor *foreground, - const GdkColor *background) -{ - PangoRenderer *renderer; - const PangoMatrix *matrix; - - g_return_if_fail (GDK_IS_DRAWABLE (drawable)); - g_return_if_fail (GDK_IS_GC (gc)); - g_return_if_fail (line != NULL); - - renderer = get_renderer (drawable, gc, foreground, background); - - /* When we have a matrix, we do positioning by adjusting the matrix, and - * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce - * a matrix when the caller didn't provide one, however, since that adds - * lots of floating point arithmetic for each glyph. - */ - matrix = pango_context_get_matrix (pango_layout_get_context (line->layout)); - if (matrix) - { - PangoMatrix tmp_matrix; - - tmp_matrix = *matrix; - tmp_matrix.x0 += x; - tmp_matrix.y0 += y; - pango_renderer_set_matrix (renderer, &tmp_matrix); - - x = 0; - y = 0; - } - /* Fall back to introduce a matrix if the coords would scale out of range. - * The x and y here will be added to in-layout coordinates. So we cannot - * support the entire range here safely. So, we just accept the middle half - * and use fallback for the rest. */ - else if (GDK_PANGO_UNITS_OVERFLOWS (x, y)) - { - PangoMatrix tmp_matrix = PANGO_MATRIX_INIT; - tmp_matrix.x0 += x; - tmp_matrix.y0 += y; - pango_renderer_set_matrix (renderer, &tmp_matrix); - - x = 0; - y = 0; - } - else - pango_renderer_set_matrix (renderer, NULL); - - pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE); - - release_renderer (renderer); -} - -/** - * gdk_draw_layout_with_colors: - * @drawable: the drawable on which to draw string - * @gc: base graphics context to use - * @x: the X position of the left of the layout (in pixels) - * @y: the Y position of the top of the layout (in pixels) - * @layout: a #PangoLayout - * @foreground: (allow-none): foreground override color, or %NULL for none - * @background: (allow-none): background override color, or %NULL for none + * Rendering a Pango layout is done most simply with pango_cairo_show_layout(); + * you can also draw pieces of the layout with pango_cairo_show_layout_line(). + * + * Draw transformed text with Pango and cairo + * + * + * #define RADIUS 100 + * #define N_WORDS 10 + * #define FONT "Sans Bold 18" * - * Render a #PangoLayout onto a #GdkDrawable, overriding the - * layout's normal colors with @foreground and/or @background. - * @foreground and @background need not be allocated. + * PangoContext *context; + * PangoLayout *layout; + * PangoFontDescription *desc; * - * If the layout's #PangoContext has a transformation matrix set, then - * @x and @y specify the position of the top left corner of the - * bounding box (in device space) of the transformed layout. + * double radius; + * int width, height; + * int i; * - * If you're using GTK+, the ususal way to obtain a #PangoLayout - * is gtk_widget_create_pango_layout(). - */ -void -gdk_draw_layout_with_colors (GdkDrawable *drawable, - GdkGC *gc, - int x, - int y, - PangoLayout *layout, - const GdkColor *foreground, - const GdkColor *background) -{ - PangoRenderer *renderer; - const PangoMatrix *matrix; - - g_return_if_fail (GDK_IS_DRAWABLE (drawable)); - g_return_if_fail (GDK_IS_GC (gc)); - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - renderer = get_renderer (drawable, gc, foreground, background); - - /* When we have a matrix, we do positioning by adjusting the matrix, and - * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce - * a matrix when the caller didn't provide one, however, since that adds - * lots of floating point arithmetic for each glyph. - */ - matrix = pango_context_get_matrix (pango_layout_get_context (layout)); - if (matrix) - { - PangoMatrix tmp_matrix; - PangoRectangle rect; - - pango_layout_get_extents (layout, NULL, &rect); - pango_matrix_transform_rectangle (matrix, &rect); - pango_extents_to_pixels (&rect, NULL); - - tmp_matrix = *matrix; - tmp_matrix.x0 += x - rect.x; - tmp_matrix.y0 += y - rect.y; - pango_renderer_set_matrix (renderer, &tmp_matrix); - - x = 0; - y = 0; - } - else if (GDK_PANGO_UNITS_OVERFLOWS (x, y)) - { - PangoMatrix tmp_matrix = PANGO_MATRIX_INIT; - tmp_matrix.x0 = x; - tmp_matrix.y0 = y; - pango_renderer_set_matrix (renderer, &tmp_matrix); - - x = 0; - y = 0; - } - else - pango_renderer_set_matrix (renderer, NULL); - - pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE); - - release_renderer (renderer); -} - -/** - * gdk_draw_layout_line: - * @drawable: the drawable on which to draw the line - * @gc: base graphics to use - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * @line: a #PangoLayoutLine + * /* Set up a transformation matrix so that the user space coordinates for + * * where we are drawing are [-RADIUS, RADIUS], [-RADIUS, RADIUS] + * * We first center, then change the scale */ * - * Render a #PangoLayoutLine onto an GDK drawable + * width = gdk_window_get_width (window); + * height = gdk_window_get_height (window); + * radius = MIN (width, height) / 2.; * - * If the layout's #PangoContext has a transformation matrix set, then - * @x and @y specify the position of the left edge of the baseline - * (left is in before-tranform user coordinates) in after-transform - * device coordinates. - */ -void -gdk_draw_layout_line (GdkDrawable *drawable, - GdkGC *gc, - gint x, - gint y, - PangoLayoutLine *line) -{ - g_return_if_fail (GDK_IS_DRAWABLE (drawable)); - g_return_if_fail (GDK_IS_GC (gc)); - g_return_if_fail (line != NULL); - - gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL); -} - -/** - * gdk_draw_layout: - * @drawable: the drawable on which to draw string - * @gc: base graphics context to use - * @x: the X position of the left of the layout (in pixels) - * @y: the Y position of the top of the layout (in pixels) - * @layout: a #PangoLayout + * cairo_translate (cr, + * radius + (width - 2 * radius) / 2, + * radius + (height - 2 * radius) / 2); + * cairo_scale (cr, radius / RADIUS, radius / RADIUS); * - * Render a #PangoLayout onto a GDK drawable + * /* Create a PangoLayout, set the font and text */ + * context = gdk_pango_context_get_for_screen (screen); + * layout = pango_layout_new (context); + * pango_layout_set_text (layout, "Text", -1); + * desc = pango_font_description_from_string (FONT); + * pango_layout_set_font_description (layout, desc); + * pango_font_description_free (desc); * - * If the layout's #PangoContext has a transformation matrix set, then - * @x and @y specify the position of the top left corner of the - * bounding box (in device space) of the transformed layout. + * /* Draw the layout N_WORDS times in a circle */ + * for (i = 0; i < N_WORDS; i++) + * { + * double red, green, blue; + * double angle = 2 * G_PI * i / n_words; * - * If you're using GTK+, the usual way to obtain a #PangoLayout - * is gtk_widget_create_pango_layout(). - */ -void -gdk_draw_layout (GdkDrawable *drawable, - GdkGC *gc, - int x, - int y, - PangoLayout *layout) -{ - g_return_if_fail (GDK_IS_DRAWABLE (drawable)); - g_return_if_fail (GDK_IS_GC (gc)); - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL); -} - -/* GdkPangoAttrStipple */ - -static PangoAttribute * -gdk_pango_attr_stipple_copy (const PangoAttribute *attr) -{ - const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr; - - return gdk_pango_attr_stipple_new (src->stipple); -} - -static void -gdk_pango_attr_stipple_destroy (PangoAttribute *attr) -{ - GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr; - - if (st->stipple) - g_object_unref (st->stipple); - - g_free (attr); -} - -static gboolean -gdk_pango_attr_stipple_compare (const PangoAttribute *attr1, - const PangoAttribute *attr2) -{ - const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1; - const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2; - - return a->stipple == b->stipple; -} - -/** - * gdk_pango_attr_stipple_new: - * @stipple: a bitmap to be set as stipple + * cairo_save (cr); * - * Creates a new attribute containing a stipple bitmap to be used when - * rendering the text. + * /* Gradient from red at angle == 60 to blue at angle == 300 */ + * red = (1 + cos (angle - 60)) / 2; + * green = 0; + * blue = 1 - red; * - * Return value: new #PangoAttribute - **/ - -PangoAttribute * -gdk_pango_attr_stipple_new (GdkBitmap *stipple) -{ - GdkPangoAttrStipple *result; - - static PangoAttrClass klass = { - 0, - gdk_pango_attr_stipple_copy, - gdk_pango_attr_stipple_destroy, - gdk_pango_attr_stipple_compare - }; - - if (!klass.type) - klass.type = gdk_pango_attr_stipple_type = - pango_attr_type_register ("GdkPangoAttrStipple"); - - result = g_new (GdkPangoAttrStipple, 1); - result->attr.klass = &klass; - - if (stipple) - g_object_ref (stipple); - - result->stipple = stipple; - - return (PangoAttribute *)result; -} - -/* GdkPangoAttrEmbossed */ - -static PangoAttribute * -gdk_pango_attr_embossed_copy (const PangoAttribute *attr) -{ - const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr; - - return gdk_pango_attr_embossed_new (e->embossed); -} - -static void -gdk_pango_attr_embossed_destroy (PangoAttribute *attr) -{ - g_free (attr); -} - -static gboolean -gdk_pango_attr_embossed_compare (const PangoAttribute *attr1, - const PangoAttribute *attr2) -{ - const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1; - const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2; - - return e1->embossed == e2->embossed; -} - -/** - * gdk_pango_attr_embossed_new: - * @embossed: if the region should be embossed + * cairo_set_source_rgb (cr, red, green, blue); + * cairo_rotate (cr, angle); * - * Creates a new attribute flagging a region as embossed or not. + * /* Inform Pango to re-layout the text with the new transformation matrix */ + * pango_cairo_update_layout (cr, layout); * - * Return value: new #PangoAttribute - **/ - -PangoAttribute * -gdk_pango_attr_embossed_new (gboolean embossed) -{ - GdkPangoAttrEmbossed *result; - - static PangoAttrClass klass = { - 0, - gdk_pango_attr_embossed_copy, - gdk_pango_attr_embossed_destroy, - gdk_pango_attr_embossed_compare - }; - - if (!klass.type) - klass.type = gdk_pango_attr_embossed_type = - pango_attr_type_register ("GdkPangoAttrEmbossed"); - - result = g_new (GdkPangoAttrEmbossed, 1); - result->attr.klass = &klass; - result->embossed = embossed; - - return (PangoAttribute *)result; -} - -/* GdkPangoAttrEmbossColor */ - -static PangoAttribute * -gdk_pango_attr_emboss_color_copy (const PangoAttribute *attr) -{ - const GdkPangoAttrEmbossColor *old = (const GdkPangoAttrEmbossColor*) attr; - GdkPangoAttrEmbossColor *copy; - - copy = g_new (GdkPangoAttrEmbossColor, 1); - copy->attr.klass = old->attr.klass; - copy->color = old->color; - - return (PangoAttribute *) copy; -} - -static void -gdk_pango_attr_emboss_color_destroy (PangoAttribute *attr) -{ - g_free (attr); -} - -static gboolean -gdk_pango_attr_emboss_color_compare (const PangoAttribute *attr1, - const PangoAttribute *attr2) -{ - const GdkPangoAttrEmbossColor *c1 = (const GdkPangoAttrEmbossColor*) attr1; - const GdkPangoAttrEmbossColor *c2 = (const GdkPangoAttrEmbossColor*) attr2; - - return color_equal (&c1->color, &c2->color); -} - -/** - * gdk_pango_attr_emboss_color_new: - * @color: a GdkColor representing the color to emboss with + * pango_layout_get_size (layout, &width, &height); * - * Creates a new attribute specifying the color to emboss text with. + * cairo_move_to (cr, - width / 2 / PANGO_SCALE, - DEFAULT_TEXT_RADIUS); + * pango_cairo_show_layout (cr, layout); * - * Return value: new #PangoAttribute + * cairo_restore (cr); + * } * - * Since: 2.12 - **/ -PangoAttribute * -gdk_pango_attr_emboss_color_new (const GdkColor *color) -{ - GdkPangoAttrEmbossColor *result; - - static PangoAttrClass klass = { - 0, - gdk_pango_attr_emboss_color_copy, - gdk_pango_attr_emboss_color_destroy, - gdk_pango_attr_emboss_color_compare - }; - - if (!klass.type) - klass.type = gdk_pango_attr_emboss_color_type = - pango_attr_type_register ("GdkPangoAttrEmbossColor"); - - result = g_new (GdkPangoAttrEmbossColor, 1); - result->attr.klass = &klass; - result->color.red = color->red; - result->color.green = color->green; - result->color.blue = color->blue; - - return (PangoAttribute *) result; -} + * g_object_unref (layout); + * g_object_unref (context); + * + * + *
+ * Output of <xref linkend="rotated-example"/> + * + *
+ */ /* Get a clip region to draw only part of a layout. index_ranges * contains alternating range starts/stops. The region is the @@ -1299,16 +188,18 @@ layout_iter_get_line_clip_region (PangoLayoutIter *iter, } /** - * gdk_pango_layout_line_get_clip_region: + * gdk_pango_layout_line_get_clip_region: (skip) * @line: a #PangoLayoutLine * @x_origin: X pixel where you intend to draw the layout line with this clip * @y_origin: baseline pixel where you intend to draw the layout line with this clip - * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes + * @index_ranges: (array): array of byte indexes into the layout, + * where even members of array are start indexes and odd elements + * are end indexes * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges * * Obtains a clip region which contains the areas where the given - * ranges of text would be drawn. @x_origin and @y_origin are the same - * position you would pass to gdk_draw_layout_line(). @index_ranges + * ranges of text would be drawn. @x_origin and @y_origin are the top left + * position of the layout. @index_ranges * should contain ranges of bytes in the layout's text. The clip * region will include space to the left or right of the line (to the * layout bounding box) if you have indexes above or below the indexes @@ -1348,7 +239,7 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line, } /** - * gdk_pango_layout_get_clip_region: + * gdk_pango_layout_get_clip_region: (skip) * @layout: a #PangoLayout * @x_origin: X pixel where you intend to draw the layout with this clip * @y_origin: Y pixel where you intend to draw the layout with this clip @@ -1356,8 +247,8 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line, * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges * * Obtains a clip region which contains the areas where the given ranges - * of text would be drawn. @x_origin and @y_origin are the same position - * you would pass to gdk_draw_layout_line(). @index_ranges should contain + * of text would be drawn. @x_origin and @y_origin are the top left point + * to center the layout. @index_ranges should contain * ranges of bytes in the layout's text. * * Note that the regions returned correspond to logical extents of the text @@ -1426,7 +317,7 @@ gdk_pango_layout_get_clip_region (PangoLayout *layout, * is more convenient if you want to keep a context around and track * changes to the screen's font rendering settings. * - * Return value: a new #PangoContext for the default display + * Return value: (transfer full): a new #PangoContext for the default display **/ PangoContext * gdk_pango_context_get (void) @@ -1452,7 +343,7 @@ gdk_pango_context_get (void) * is more convenient if you want to keep a context around and track * changes to the screen's font rendering settings. * - * Return value: a new #PangoContext for @screen + * Return value: (transfer full): a new #PangoContext for @screen * * Since: 2.2 **/ @@ -1463,12 +354,11 @@ gdk_pango_context_get_for_screen (GdkScreen *screen) PangoContext *context; const cairo_font_options_t *options; double dpi; - + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); fontmap = pango_cairo_font_map_get_default (); - - context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap)); + context = pango_font_map_create_context (fontmap); options = gdk_screen_get_font_options (screen); pango_cairo_context_set_font_options (context, options); @@ -1478,6 +368,3 @@ gdk_pango_context_get_for_screen (GdkScreen *screen) return context; } - -#define __GDK_PANGO_C__ -#include "gdkaliasdef.c"