]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkpango.c
Translation updated by Ivar Smolin.
[~andy/gtk] / gdk / gdkpango.c
index 0f24309d366b8f82f5028361fcd4b562bf759880..52dcfebd4166c798204ab4ddd4e7a6a0544d4677 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#include <config.h>
+#include <math.h>
+#include <pango/pangocairo.h>
+#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 "gdkalias.h"
+
+/* This is for P_() ... a bit non-kosher, but works fine */
+#include "gtk/gtkintl.h"
 
 #define GDK_INFO_KEY "gdk-info"
 
-typedef struct _GdkPangoContextInfo GdkPangoContextInfo;
+/* 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 _GdkPangoContextInfo
+struct _GdkPangoRendererPrivate
 {
-  GdkColormap *colormap;
+  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];
+  gboolean embossed;
+
+  cairo_t *cr;
+  PangoRenderPart last_part;
+
+  /* Current target */
+  GdkDrawable *drawable;
+  GdkGC *base_gc;
 };
 
 static PangoAttrType gdk_pango_attr_stipple_type;
 static PangoAttrType gdk_pango_attr_embossed_type;
 
-static void gdk_pango_get_item_properties (PangoItem      *item,
-                                          PangoUnderline *uline,
-                                          gboolean       *strikethrough,
-                                           gint           *rise,
-                                          PangoColor     *fg_color,
-                                          gboolean       *fg_set,
-                                          PangoColor     *bg_color,
-                                          gboolean       *bg_set,
-                                           gboolean       *embossed,
-                                           GdkBitmap     **stipple,
-                                          gboolean       *shape_set,
-                                          PangoRectangle *ink_rect,
-                                          PangoRectangle *logical_rect);
+enum {
+  PROP_0,
+  PROP_SCREEN
+};
+
+G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
 
 static void
-gdk_pango_context_destroy (GdkPangoContextInfo *info)
+gdk_pango_renderer_finalize (GObject *object)
 {
-  if (info->colormap)
-    g_object_unref (info->colormap);
-  g_free (info);
+  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 GdkPangoContextInfo *
-gdk_pango_context_get_info (PangoContext *context, gboolean create)
+static GObject*
+gdk_pango_renderer_constructor (GType                  type,
+                               guint                  n_construct_properties,
+                               GObjectConstructParam *construct_params)
 {
-  GdkPangoContextInfo *info =
-    g_object_get_qdata (G_OBJECT (context),
-                        g_quark_try_string (GDK_INFO_KEY));
-  if (!info && create)
-    {
-      info = g_new (GdkPangoContextInfo, 1);
-      info->colormap = NULL;
+  GObject *object;
+  GdkPangoRenderer *gdk_renderer;
+
+  object = (* G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor) (type,
+                                                                             n_construct_properties,
+                                                                             construct_params);
 
-      g_object_set_qdata_full (G_OBJECT (context),
-                               g_quark_from_static_string (GDK_INFO_KEY),
-                               info, (GDestroyNotify)gdk_pango_context_destroy);
+  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 info;
+  return object;
+}
+
+/* Adjusts matrix and color for the renderer to draw the secondary
+ * "shadow" copy for embossed text */
+static void
+emboss_context (cairo_t *cr)
+{
+  cairo_matrix_t tmp_matrix;
+
+  /* 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);
+
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 }
 
-static GdkGC *
-gdk_pango_get_gc (GdkDrawable    *drawable,
-                 PangoContext   *context,
-                 PangoColor     *fg_color,
-                  GdkBitmap      *stipple,
-                 GdkGC          *base_gc)
+static cairo_t *
+get_cairo_context (GdkPangoRenderer *gdk_renderer,
+                  PangoRenderPart   part)
 {
-  GdkGC *result;
-  GdkPangoContextInfo *info;
+  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);
+       }
+    }
   
-  g_return_val_if_fail (context != NULL, NULL);
+  priv->last_part = (PangoRenderPart)-1;
+  if (part != priv->last_part)
+    {
+      PangoColor *pango_color = pango_renderer_get_color (renderer,
+                                                         part);
+      GdkColor *color = NULL;
+      GdkColor tmp_color;
+      if (pango_color)
+       {
+         tmp_color.red = pango_color->red;
+         tmp_color.green = pango_color->green;
+         tmp_color.blue = pango_color->blue;
+         
+         color = &tmp_color;
+       }
+
+      _gdk_gc_update_context (priv->base_gc,
+                             priv->cr,
+                             color,
+                             priv->stipple[part]);
+      priv->last_part = part;
+    }
 
-  info = gdk_pango_context_get_info (context, FALSE);
+  return priv->cr;
+}
 
-  if (info == NULL || info->colormap == NULL)
+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)
     {
-      g_warning ("you must set the colormap on a PangoContext before using it to draw a layout");
-      return NULL;
+      cairo_save (cr);
+      emboss_context (cr);
+      cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
+      pango_cairo_show_glyph_string (cr, font, glyphs);
+      cairo_restore (cr);
     }
+  
+  cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
+  pango_cairo_show_glyph_string (cr, font, glyphs);
+}
 
-  result = gdk_gc_new (drawable);
-  gdk_gc_copy (result, base_gc);
+/* Draws an error underline that looks like one of:
+ *              H       E                H
+ *     /\      /\      /\        /\      /\               -
+ *   A/  \    /  \    /  \     A/  \    /  \              |
+ *    \   \  /    \  /   /D     \   \  /    \             |
+ *     \   \/  C   \/   /        \   \/   C  \            | height = HEIGHT_SQUARES * square
+ *      \      /\  F   /          \  F   /\   \           | 
+ *       \    /  \    /            \    /  \   \G         |
+ *        \  /    \  /              \  /    \  /          |
+ *         \/      \/                \/      \/           -
+ *         B                         B       
+ *    |----|
+ *   unit_width = (HEIGHT_SQUARES - 1) * square
+ *
+ * The x, y, width, height passed in give the desired bounding box;
+ * x/width are adjusted to make the underline a integer number of units
+ * wide.
+ */
+#define HEIGHT_SQUARES 2.5
+
+static void
+draw_error_underline (cairo_t *cr,
+                     double  x,
+                     double  y,
+                     double  width,
+                     double  height)
+{
+  double square = height / HEIGHT_SQUARES;
+  double unit_width = (HEIGHT_SQUARES - 1) * square;
+  int width_units = (width + unit_width / 2) / unit_width;
+  double y_top, y_bottom;
+  int i;
+
+  x += (width - width_units * unit_width);
+  width = width_units * unit_width;
+
+  y_top = y;
+  y_bottom = y + height;
+  
+  /* Bottom of squiggle */
+  cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
+  for (i = 0; i < width_units; i += 2)
+    {
+      double x_middle = x + (i + 1) * unit_width;
+      double x_right = x + (i + 2) * unit_width;
+    
+      cairo_line_to (cr, x_middle, y_bottom); /* B */
+      
+      if (i + 1 == width_units)
+       /* Nothing */;
+      else if (i + 2 == width_units)
+       cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
+      else
+       cairo_line_to (cr, x_right, y_top + square); /* C */
+    }
   
-  if (fg_color)
+  /* Top of squiggle */
+  for (i -= 2; i >= 0; i -= 2)
     {
-      GdkColor color;
+      double x_left = x + i * unit_width;
+      double x_middle = x + (i + 1) * unit_width;
+      double x_right = x + (i + 2) * unit_width;
+      
+      if (i + 1 == width_units)
+       cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
+      else {
+       if (i + 2 == width_units)
+         cairo_line_to (cr, x_right, y_top); /* E */
+       cairo_line_to (cr, x_middle, y_bottom - square); /* F */
+      }
       
-      color.red = fg_color->red;
-      color.green = fg_color->green;
-      color.blue = fg_color->blue;
+      cairo_line_to (cr, x_left, y_top);   /* H */
+    }
 
-      gdk_rgb_find_color (info->colormap, &color);
-      gdk_gc_set_foreground (result, &color);
+  cairo_close_path (cr);
+  cairo_fill (cr);
+}
+
+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 (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);
     }
 
-  if (stipple)
+  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 (cr);
+      draw_error_underline (cr,
+                           (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+                           (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+      cairo_restore (cr);
+    }
+
+  draw_error_underline (cr,
+                       (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+                       (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+}
+
+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;
+  GSList *l;
+  int i;
+  
+  embossed = FALSE;
+  stipple = NULL;
+  
+  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;
+       }
+    }
+
+  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_gc_set_fill (result, GDK_STIPPLED);
-      gdk_gc_set_stipple (result, stipple);
+      gdk_renderer->priv->embossed = embossed;
+      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;
+}
+
+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->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;
   
-  return result;
+  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
-gdk_pango_free_gc (PangoContext *context,
-                  GdkGC        *gc)
+on_renderer_display_closed (GdkDisplay       *display,
+                           GdkPangoRenderer *renderer)
 {
-  g_object_unref (gc);
+  g_signal_handlers_disconnect_by_func (renderer->priv->screen,
+                                       (gpointer)on_renderer_display_closed,
+                                       renderer);
+  g_object_set_data (G_OBJECT (renderer->priv->screen), "gdk-pango-renderer", NULL);
 }
 
 /**
- * gdk_pango_context_set_colormap:
- * @context: a #PangoContext
- * @colormap: a #GdkColormap
+ * 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.
  *
- * Sets the colormap to be used for drawing with @context.
+ * 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), "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: the new target drawable, or %NULL
+ * 
+ * Sets the drawable the renderer draws to.
  *
- * If you obtained your context from gtk_widget_get_pango_context() or
- * gtk_widget_create_pango_context(), the colormap will already be set
- * to the colormap for the widget, so you shouldn't need this
- * function.
+ * Since: 2.6
  **/
 void
-gdk_pango_context_set_colormap (PangoContext *context,
-                               GdkColormap  *colormap)
+gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
+                                GdkDrawable      *drawable)
 {
-  GdkPangoContextInfo *info;
+  GdkPangoRendererPrivate *priv;
   
-  g_return_if_fail (context != NULL);
+  g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
+  g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
 
-  info = gdk_pango_context_get_info (context, TRUE);
-  g_return_if_fail (info != NULL);
+  priv = gdk_renderer->priv;
   
-  if (info->colormap != colormap)
+  if (priv->drawable != drawable)
     {
-      if (info->colormap)
-       g_object_unref (info->colormap);
+      if (priv->drawable)
+       g_object_unref (priv->drawable);
+      priv->drawable = drawable;
+      if (priv->drawable)
+       g_object_ref (priv->drawable);
+    }
+}
 
-      info->colormap = colormap;
+/**
+ * gdk_pango_renderer_set_gc:
+ * @gdk_renderer: a #GdkPangoRenderer
+ * @gc: 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);
+    }
+}
+
+
+/**
+ * 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.
+ *
+ * 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 (info->colormap)
-       g_object_ref (info->colormap);
+      if (gdk_renderer->priv->stipple[part])
+       g_object_ref (gdk_renderer->priv->stipple[part]);
+
+      pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
     }
 }
 
-static void
-draw_underline (GdkDrawable    *drawable,
-               GdkGC          *gc,
-               PangoUnderline  uline,
-               int             baseline_y,
-               int             low_y,
-               int             start_x,
-               int             end_x)
-{
-  switch (uline)
+/**
+ * gdk_pango_renderer_set_override_color:
+ * @gdk_renderer: a #GdkPangoRenderer
+ * @part: the part to render to set the color of
+ * @color: 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)
     {
-    case PANGO_UNDERLINE_NONE:
-      break;
-    case PANGO_UNDERLINE_DOUBLE:
-      gdk_draw_line (drawable, gc,
-                    start_x, baseline_y + 3,
-                    end_x,   baseline_y + 3);
-      /* Fall through */
-    case PANGO_UNDERLINE_SINGLE:
-      gdk_draw_line (drawable, gc,
-                    start_x, baseline_y + 1,
-                    end_x,   baseline_y + 1);
-      break;
-    case PANGO_UNDERLINE_LOW:
-      gdk_draw_line (drawable, gc,
-                    start_x, low_y + 1,
-                    end_x,   low_y + 1);
-      break;
+      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;
+}
+
+/**
+ * gdk_pango_context_set_colormap:
+ * @context: a #PangoContext
+ * @colormap: a #GdkColormap
+ *
+ * This function used to set the colormap to be used for drawing with
+ * @context. The colormap is now always derived from the graphics
+ * context used for drawing, so calling this function is no longer
+ * necessary.
+ **/
+void
+gdk_pango_context_set_colormap (PangoContext *context,
+                               GdkColormap  *colormap)
+{
+  g_return_if_fail (PANGO_IS_CONTEXT (context));
+  g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
+}
+
+/* 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);
 }
 
 /**
@@ -207,6 +824,11 @@ draw_underline (GdkDrawable    *drawable,
  * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
  * layout's normal colors with @foreground and/or @background.
  * @foreground and @background need not be allocated.
+ *
+ * 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,
@@ -214,218 +836,91 @@ gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
                                   gint              x, 
                                   gint              y,
                                   PangoLayoutLine  *line,
-                                  GdkColor         *foreground,
-                                  GdkColor         *background)
+                                  const GdkColor   *foreground,
+                                  const GdkColor   *background)
 {
-  GSList *tmp_list = line->runs;
-  PangoRectangle overall_rect;
-  PangoRectangle logical_rect;
-  PangoRectangle ink_rect;
-  PangoContext *context;
-  gint x_off = 0;
-  gint rise = 0;
-  gboolean embossed;
-  GdkBitmap *stipple;
-  PangoUnderline last_uline = PANGO_UNDERLINE_NONE;
-  gint uline_start_x = 0;
-  gint uline_end_x = 0;
-  gint uline_end_x_extended = 0;
-  gint last_risen_y = 0;
-  gint low_y = G_MININT;
-  GdkGC *last_fg_gc = NULL;
-  gboolean last_fg_set = FALSE;
-  PangoColor last_fg_color;
-
+  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);
 
-  context = pango_layout_get_context (line->layout);
-  
-  pango_layout_line_get_extents (line,NULL, &overall_rect);
-  
-  while (tmp_list)
+  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)
     {
-      PangoUnderline this_uline = PANGO_UNDERLINE_NONE;
-      PangoLayoutRun *run = tmp_list->data;
-      PangoColor fg_color, bg_color;
-      gboolean strike, fg_set, bg_set, shape_set;
-      GdkGC *fg_gc;
-      gint risen_y;
-      
-      tmp_list = tmp_list->next;
+      PangoMatrix tmp_matrix;
       
-      gdk_pango_get_item_properties (run->item, &this_uline,
-                                    &strike,
-                                     &rise,
-                                     &fg_color, &fg_set,
-                                     &bg_color, &bg_set,
-                                     &embossed,
-                                     &stipple,
-                                     &shape_set,
-                                     &ink_rect,
-                                    &logical_rect);
-
-      /* we subtract the rise because X coordinates are upside down */
-      risen_y = y - rise / PANGO_SCALE;
-      
-      if (!shape_set)
-       {
-         if (this_uline == PANGO_UNDERLINE_NONE)
-           pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
-                                       NULL, &logical_rect);
-         else
-           pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
-                                       &ink_rect, &logical_rect);
-       }
+      tmp_matrix = *matrix;
+      tmp_matrix.x0 = x;
+      tmp_matrix.y0 = y;
+      pango_renderer_set_matrix (renderer, &tmp_matrix);
 
-      if (bg_set || background)
-       {
-         GdkGC *bg_gc;
-          PangoColor tmp = bg_color;
-          
-          if (background)
-            {
-              tmp.red = background->red;
-              tmp.blue = background->blue;
-              tmp.green = background->green;
-            }
-          
-          bg_gc = gdk_pango_get_gc (drawable, context, &tmp, stipple, gc);
-          
-         gdk_draw_rectangle (drawable, bg_gc, TRUE,
-                             x + (x_off + logical_rect.x) / PANGO_SCALE,
-                             risen_y + overall_rect.y / PANGO_SCALE,
-                             logical_rect.width / PANGO_SCALE,
-                             overall_rect.height / PANGO_SCALE);
-
-          if (stipple)
-            gdk_gc_set_fill (bg_gc, GDK_SOLID);
-          
-         gdk_pango_free_gc (context, bg_gc);
-       }
+      x = 0;
+      y = 0;
+    }
+  else
+    pango_renderer_set_matrix (renderer, NULL);
 
-      if (fg_set || stipple || foreground)
-        {
-          PangoColor tmp = fg_color;
-          
-          if (foreground)
-            {
-              tmp.red = foreground->red;
-              tmp.blue = foreground->blue;
-              tmp.green = foreground->green;
-            }
-          
-          fg_gc = gdk_pango_get_gc (drawable, context, (fg_set || foreground) ? &tmp : NULL,
-                                    stipple, gc);
-        }
-      else
-       fg_gc = gc;
+  pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
 
-      if (!shape_set)
-        {
-          gint gx, gy;
+  release_renderer (renderer);
+}
 
-          gx = x + x_off / PANGO_SCALE;
-          gy = risen_y;
-          
-          if (embossed)
-            {
-              PangoColor color = { 65535, 65535, 65535 };
-              GdkGC *white_gc = gdk_pango_get_gc (drawable, context, &color, stipple, fg_gc);
-              gdk_draw_glyphs (drawable, white_gc, run->item->analysis.font,
-                               gx + 1,
-                               gy + 1,
-                               run->glyphs);
-              gdk_pango_free_gc (context, white_gc);
-            }
-          
-          gdk_draw_glyphs (drawable, fg_gc, run->item->analysis.font,
-                           gx, gy,
-                           run->glyphs);
-        }
+/* Gets the bounds of a layout in device coordinates. Note cut-and-paste
+ * between here and gtklabel.c */
+static void
+get_rotated_layout_bounds (PangoLayout  *layout,
+                          GdkRectangle *rect)
+{
+  PangoContext *context = pango_layout_get_context (layout);
+  const PangoMatrix *matrix = pango_context_get_matrix (context);
+  gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
+  PangoRectangle logical_rect;
+  gint i, j;
 
-      if (this_uline != last_uline ||
-         risen_y != last_risen_y ||
-         fg_set != last_fg_set ||
-         (fg_set && (last_fg_color.red != fg_color.red ||
-                     last_fg_color.green != fg_color.green ||
-                     last_fg_color.blue != fg_color.blue)))
+  pango_layout_get_extents (layout, NULL, &logical_rect);
+  
+  for (i = 0; i < 2; i++)
+    {
+      gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
+      for (j = 0; j < 2; j++)
        {
-         /* If only color changes, the underlines extend to the edge
-          * of the logical rectangle so they join up; otherwise they
-          * go 1 pixel beyond the ink rectangle. This doesn't work
-          * for low underlines (they will be at a different y anyways),
-          * so they follow the normal path.
-          */
-         gboolean extend_uline = (this_uline == last_uline &&
-                                  this_uline != PANGO_UNDERLINE_LOW &&
-                                  risen_y == last_risen_y);
+         gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
+         
+         gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
+         gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
          
-         /* Starting a new underline run
-          */
-         if (last_uline != PANGO_UNDERLINE_NONE)
+         if (i == 0 && j == 0)
            {
-             draw_underline (drawable, last_fg_gc, last_uline,
-                             last_risen_y, low_y,
-                             uline_start_x,
-                             extend_uline ? uline_end_x_extended : uline_end_x);
+             x_min = x_max = xt;
+             y_min = y_max = yt;
            }
-
-         if (this_uline != PANGO_UNDERLINE_NONE)
+         else
            {
-             if (extend_uline)
-               uline_start_x = x + x_off / PANGO_SCALE;
-             else
-               uline_start_x = x + (x_off + ink_rect.x) / PANGO_SCALE - 1;
-
-             low_y = G_MININT;
+             if (xt < x_min)
+               x_min = xt;
+             if (yt < y_min)
+               y_min = yt;
+             if (xt > x_max)
+               x_max = xt;
+             if (yt > y_max)
+               y_max = yt;
            }
        }
-
-      /* Update current underline segment information
-       */
-      if (this_uline != PANGO_UNDERLINE_NONE)
-       {
-         uline_end_x = x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE;
-         uline_end_x_extended = x + (x_off + logical_rect.x + logical_rect.width) / PANGO_SCALE - 1;
-       }
-
-      if (this_uline == PANGO_UNDERLINE_LOW)
-       low_y = MAX (low_y, risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE);
-
-      if (strike)
-       {
-         int centerline = logical_rect.y + logical_rect.height / 2;
-         
-         gdk_draw_line (drawable, fg_gc,
-                        x + (x_off + logical_rect.x) / PANGO_SCALE - 1,
-                        risen_y + centerline / PANGO_SCALE,
-                        x + (x_off + logical_rect.x + logical_rect.width) / PANGO_SCALE + 1,
-                        risen_y + centerline / PANGO_SCALE);
-       }
-
-      if (last_fg_gc != gc && last_fg_gc)
-       gdk_pango_free_gc (context, last_fg_gc);
-
-      last_risen_y = risen_y;
-      last_uline = this_uline;
-      last_fg_gc = fg_gc;
-      last_fg_set = fg_set;
-      if (fg_set)
-       last_fg_color = fg_color;
-      
-      x_off += logical_rect.width;
     }
-
-  /* Finish off any remaining underlines
-   */
-  if (last_uline != PANGO_UNDERLINE_NONE)
-    draw_underline (drawable, last_fg_gc, last_uline, last_risen_y, low_y,
-                   uline_start_x, uline_end_x);
-
-  if (last_fg_gc != gc && last_fg_gc)
-    gdk_pango_free_gc (context, last_fg_gc);
+  
+  rect->x = floor (x_min);
+  rect->width = ceil (x_max) - rect->x;
+  rect->y = floor (y_min);
+  rect->height = floor (y_max) - rect->y;
 }
 
 /**
@@ -442,6 +937,10 @@ gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
  * layout's normal colors with @foreground and/or @background.
  * @foreground and @background need not be allocated.
  *
+ * 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.
+ *
  * If you're using GTK+, the ususal way to obtain a #PangoLayout
  * is gtk_widget_create_pango_layout().
  */
@@ -451,38 +950,45 @@ gdk_draw_layout_with_colors (GdkDrawable     *drawable,
                              int              x, 
                              int              y,
                              PangoLayout     *layout,
-                             GdkColor        *foreground,
-                             GdkColor        *background)
+                             const GdkColor  *foreground,
+                             const GdkColor  *background)
 {
-  PangoLayoutIter *iter;
+  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));
 
-  iter = pango_layout_get_iter (layout);
-  
-  do
+  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)
     {
-      PangoRectangle logical_rect;
-      PangoLayoutLine *line;
-      int baseline;
-      
-      line = pango_layout_iter_get_line (iter);
+      PangoMatrix tmp_matrix;
+      GdkRectangle rect;
+
+      get_rotated_layout_bounds (layout, &rect);
       
-      pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
-      baseline = pango_layout_iter_get_baseline (iter);
+      tmp_matrix = *matrix;
+      tmp_matrix.x0 += x - rect.x;
+      tmp_matrix.y0 += y - rect.y;
+      pango_renderer_set_matrix (renderer, &tmp_matrix);
       
-      gdk_draw_layout_line_with_colors (drawable, gc,
-                                        x + logical_rect.x / PANGO_SCALE,
-                                        y + baseline / PANGO_SCALE,
-                                        line,
-                                        foreground,
-                                        background);
+      x = 0;
+      y = 0;
     }
-  while (pango_layout_iter_next_line (iter));
+  else
+    pango_renderer_set_matrix (renderer, NULL);
 
-  pango_layout_iter_free (iter);
+  pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
+  
+  release_renderer (renderer);
 }
 
 /**
@@ -494,6 +1000,11 @@ gdk_draw_layout_with_colors (GdkDrawable     *drawable,
  * @line:      a #PangoLayoutLine
  *
  * Render a #PangoLayoutLine onto an GDK drawable
+ *
+ * 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,
@@ -519,7 +1030,11 @@ gdk_draw_layout_line (GdkDrawable      *drawable,
  *
  * Render a #PangoLayout onto a GDK drawable
  *
- * If you're using GTK+, the ususal way to obtain a #PangoLayout
+ * 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.
+ *
+ * If you're using GTK+, the usual way to obtain a #PangoLayout
  * is gtk_widget_create_pango_layout().
  */
 void 
@@ -536,110 +1051,6 @@ gdk_draw_layout (GdkDrawable     *drawable,
   gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
 }
 
-static void
-gdk_pango_get_item_properties (PangoItem      *item,
-                              PangoUnderline *uline,
-                              gboolean       *strikethrough,
-                               gint           *rise,
-                              PangoColor     *fg_color,
-                              gboolean       *fg_set,
-                              PangoColor     *bg_color,
-                              gboolean       *bg_set,
-                               gboolean       *embossed,
-                               GdkBitmap     **stipple,
-                              gboolean       *shape_set,
-                              PangoRectangle *ink_rect,
-                              PangoRectangle *logical_rect)
-{
-  GSList *tmp_list = item->analysis.extra_attrs;
-
-  if (strikethrough)
-      *strikethrough = FALSE;
-  
-  if (fg_set)
-    *fg_set = FALSE;
-  
-  if (bg_set)
-    *bg_set = FALSE;
-
-  if (shape_set)
-    *shape_set = FALSE;
-
-  if (rise)
-    *rise = 0;
-
-  if (embossed)
-    *embossed = FALSE;
-
-  if (stipple)
-    *stipple = NULL;
-  
-  while (tmp_list)
-    {
-      PangoAttribute *attr = tmp_list->data;
-
-      switch (attr->klass->type)
-       {
-       case PANGO_ATTR_UNDERLINE:
-         if (uline)
-           *uline = ((PangoAttrInt *)attr)->value;
-         break;
-
-       case PANGO_ATTR_STRIKETHROUGH:
-           if (strikethrough)
-               *strikethrough = ((PangoAttrInt *)attr)->value;
-           break;
-           
-       case PANGO_ATTR_FOREGROUND:
-         if (fg_color)
-           *fg_color = ((PangoAttrColor *)attr)->color;
-         if (fg_set)
-           *fg_set = TRUE;
-         
-         break;
-         
-       case PANGO_ATTR_BACKGROUND:
-         if (bg_color)
-           *bg_color = ((PangoAttrColor *)attr)->color;
-         if (bg_set)
-           *bg_set = TRUE;
-         
-         break;
-
-       case PANGO_ATTR_SHAPE:
-         if (shape_set)
-           *shape_set = TRUE;
-         if (logical_rect)
-           *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
-         if (ink_rect)
-           *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
-         break;
-
-        case PANGO_ATTR_RISE:
-          if (rise)
-            *rise = ((PangoAttrInt *)attr)->value;
-          break;
-          
-       default:
-          /* stipple_type and embossed_type aren't necessarily
-           * initialized, but they are 0, which is an
-           * invalid type so won't occur. 
-           */
-          if (stipple && attr->klass->type == gdk_pango_attr_stipple_type)
-            {
-              *stipple = ((GdkPangoAttrStipple*)attr)->stipple;
-            }
-          else if (embossed && attr->klass->type == gdk_pango_attr_embossed_type)
-            {
-              *embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
-            }
-         break;
-       }
-      tmp_list = tmp_list->next;
-    }
-}
-
-
 static PangoAttribute *
 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
 {
@@ -825,12 +1236,14 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
 
       /* Note that get_x_ranges returns layout coordinates
        */
-      pango_layout_line_get_x_ranges (line,
-                                      index_ranges[i*2],
-                                      index_ranges[i*2+1],
-                                      &pixel_ranges, &n_pixel_ranges);
+      if (index_ranges[i*2+1] >= line->start_index &&
+         index_ranges[i*2] < line->start_index + line->length)
+       pango_layout_line_get_x_ranges (line,
+                                       index_ranges[i*2],
+                                       index_ranges[i*2+1],
+                                       &pixel_ranges, &n_pixel_ranges);
   
-      for (j=0; j < n_pixel_ranges; j++)
+      for (j = 0; j < n_pixel_ranges; j++)
         {
           GdkRectangle rect;
           
@@ -927,3 +1340,34 @@ gdk_pango_context_get (void)
 {
   return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
 }
+
+/**
+ * gdk_pango_context_get_for_screen:
+ * @screen: the #GdkScreen for which the context is to be created.
+ * 
+ * Creates a #PangoContext for @screen.
+ *
+ * The context must be freed when you're finished with it.
+ * 
+ * When using GTK+, normally you should use gtk_widget_get_pango_context()
+ * instead of this function, to get the appropriate context for
+ * the widget you intend to render text onto.
+ * 
+ * Return value: a new #PangoContext for @screen
+ *
+ * Since: 2.2
+ **/
+PangoContext *
+gdk_pango_context_get_for_screen (GdkScreen *screen)
+{
+  PangoFontMap *fontmap;
+  
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  fontmap = pango_cairo_font_map_get_default ();
+  
+  return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
+}
+
+#define __GDK_PANGO_C__
+#include "gdkaliasdef.c"