]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkpango.c
Updated Bulgarian translation by Alexander Shopov <ash@contact.bg>
[~andy/gtk] / gdk / gdkpango.c
index d317b0faab355c6af23c12f39bde074a2e76e227..6bc0cffdf26f52faa8073bbf8bbc929143ccd94e 100644 (file)
 
 #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 "gdkintl.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"
 
 /* We have various arrays indexed by render part; if PangoRenderPart
@@ -47,33 +48,22 @@ struct _GdkPangoRendererPrivate
   gboolean override_color_set[MAX_RENDER_PART + 1];
   
   GdkBitmap *stipple[MAX_RENDER_PART + 1];
+  PangoColor emboss_color;
   gboolean embossed;
 
-  /* When switching between the normal and shadow copies when
-   * drawing shadows we can get unexpected recursion into the
-   * drawing functions; the 'in_emboss' flag guards against that.
-   */
-  gboolean in_emboss;
+  cairo_t *cr;
+  PangoRenderPart last_part;
 
   /* Current target */
   GdkDrawable *drawable;
   GdkGC *base_gc;
 
-  /* Cached GC, derived from base_gc */
-  GdkGC *gc;
-  PangoColor gc_color;
-  gboolean gc_color_set;
-  GdkBitmap *gc_stipple;
-  
-  /* we accumulate trapezoids for the same PangoRenderPart */
-  GArray *trapezoids;
-  PangoRenderPart trapezoid_part;
+  gboolean gc_changed;
 };
 
 static PangoAttrType gdk_pango_attr_stipple_type;
 static PangoAttrType gdk_pango_attr_embossed_type;
-
-static void flush_trapezoids (GdkPangoRenderer *gdk_renderer);
+static PangoAttrType gdk_pango_attr_emboss_color_type;
 
 enum {
   PROP_0,
@@ -89,10 +79,6 @@ gdk_pango_renderer_finalize (GObject *object)
   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
   int i;
 
-  if (priv->gc)
-    g_object_unref (priv->gc);
-  if (priv->gc_stipple)
-    g_object_unref (priv->gc_stipple);
   if (priv->base_gc)
     g_object_unref (priv->base_gc);
   if (priv->drawable)
@@ -102,8 +88,6 @@ gdk_pango_renderer_finalize (GObject *object)
     if (priv->stipple[i])
       g_object_unref (priv->stipple[i]);
 
-  g_array_free (priv->trapezoids, TRUE);
-
   G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
 }
 
@@ -130,154 +114,114 @@ gdk_pango_renderer_constructor (GType                  type,
   return object;
 }
 
-/* Adjusts matrix and color for the renderer to draw the secondar
+/* Adjusts matrix and color for the renderer to draw the secondary
  * "shadow" copy for embossed text */
 static void
-emboss_renderer (PangoRenderer   *renderer,
-                PangoRenderPart  part,
-                PangoMatrix    **save_matrix,
-                PangoColor     **save_color)
+emboss_context (GdkPangoRenderer *renderer, cairo_t *cr)
 {
-  GdkPangoRendererPrivate *priv = GDK_PANGO_RENDERER(renderer)->priv;
-  static const PangoColor white = { 0xffff, 0xffff, 0xffff };
-  PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
+  GdkPangoRendererPrivate *priv = renderer->priv;
+  cairo_matrix_t tmp_matrix;
+  double red, green, blue;
 
-  priv->in_emboss = TRUE;
-  
-  *save_color = pango_renderer_get_color (renderer, part);
-  if (*save_color)
-    *save_color = pango_color_copy (*save_color);
-  
-  *save_matrix = renderer->matrix;
-  if (*save_matrix)
-    {
-      *save_matrix = pango_matrix_copy (*save_matrix);
-      tmp_matrix = **save_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
    */
-  tmp_matrix.x0 += 1;
-  tmp_matrix.y0 += 1;
-  
-  pango_renderer_set_matrix (renderer, &tmp_matrix);
-  pango_renderer_set_color (renderer, part, &white);
+  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);
 }
 
-/* Restores from emboss_renderer() */
-static void
-unemboss_renderer (PangoRenderer   *renderer,
-                  PangoRenderPart  part,
-                  PangoMatrix    **save_matrix,
-                  PangoColor     **save_color)
+static inline gboolean
+color_equal (const PangoColor *c1, const PangoColor *c2)
 {
-  GdkPangoRendererPrivate *priv = GDK_PANGO_RENDERER(renderer)->priv;
-  pango_renderer_set_matrix (renderer, *save_matrix);
-  pango_renderer_set_color (renderer, part, *save_color);
+  if (!c1 && !c2)
+    return TRUE;
 
-  if (*save_matrix)
-    pango_matrix_free (*save_matrix);
-  if (*save_color)
-    pango_color_free (*save_color);
+  if (c1 && c2 &&
+      c1->red == c2->red &&
+      c1->green == c2->green &&
+      c1->blue == c2->blue)
+    return TRUE;
 
-  priv->in_emboss = FALSE;
+  return FALSE;
 }
 
-/* Gets the GC for drawing @part. This make involve copying the base GC
- * for the renderer, in which case we keep a one-GC cache. */
-static GdkGC *
-get_gc (GdkPangoRenderer *gdk_renderer,
-       PangoRenderPart   part)
+static cairo_t *
+get_cairo_context (GdkPangoRenderer *gdk_renderer,
+                  PangoRenderPart   part)
 {
   PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
-  PangoColor *color;
-  GdkBitmap *stipple;
   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
 
-  color = pango_renderer_get_color (renderer, part);
-
-  if (part <= MAX_RENDER_PART)
-    stipple = priv->stipple[part];
-  else
-    stipple = NULL;
-
-  if (!color && !stipple)      /* nothing override, use base_gc */
-    return priv->base_gc;
-  else
+  if (!priv->cr)
     {
-      gboolean new_stipple = FALSE;
-      gboolean new_color = FALSE;
-      
-      if (stipple != priv->gc_stipple)
-       new_stipple = TRUE;
-
-      if ((priv->gc_color_set && !color) ||
-         (!priv->gc_color_set && color) ||
-         priv->gc_color.red != color->red ||
-         priv->gc_color.green != color->green ||
-         priv->gc_color.blue != color->blue)
-       new_color = TRUE;
+      const PangoMatrix *matrix;
       
-      if (!priv->gc)
-       {
-         priv->gc = gdk_gc_new (priv->drawable);
-         gdk_gc_copy (priv->gc, priv->base_gc);
-       }
-      else if (new_color && priv->gc_color_set && !color)
-       {
-         /* We have to recopy the original GC onto the cached GC
-          * to get the default color */
-         new_stipple = TRUE;
-         gdk_gc_copy (priv->gc, priv->base_gc);
-       }
-      else if (new_stipple && priv->gc_stipple && !stipple)
+      priv->cr = gdk_cairo_create (priv->drawable);
+
+      matrix = pango_renderer_get_matrix (renderer);
+      if (matrix)
        {
-         /* Similarly, we need to make a new copy to restore to the
-          * default stipple state (the caller may have set a stipple
-          * on the GC, and even if not, gdk_gc_set_stipple (gc, NULL)
-          * doesn't work currently to restore to the default X stipple) */
-         new_color = TRUE;
-         gdk_gc_copy (priv->gc, priv->base_gc);
+         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;
 
-      if (new_color)
+      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 (color)
+         if (pango_color)
            {
-             GdkColor gdk_color;
-
-             gdk_color.red = color->red;
-             gdk_color.green = color->green;
-             gdk_color.blue = color->blue;
+             tmp_color.red = pango_color->red;
+             tmp_color.green = pango_color->green;
+             tmp_color.blue = pango_color->blue;
              
-             gdk_gc_set_rgb_fg_color (priv->gc, &gdk_color);
-
-             priv->gc_color = *color;
-             priv->gc_color_set = TRUE;
+             color = &tmp_color;
            }
          else
-           priv->gc_color_set = FALSE;
-       }
+           color = NULL;
 
-      if (new_stipple)
-       {
-         if (priv->gc_stipple)
-           g_object_unref (priv->gc_stipple);
-
-         if (stipple)
-           {
-             gdk_gc_set_stipple (priv->gc, stipple);
-             gdk_gc_set_fill (priv->gc, GDK_STIPPLED);
-             priv->gc_stipple = g_object_ref (stipple);
-           }
-         else
-           priv->gc_stipple = NULL;
+         _gdk_gc_update_context (priv->base_gc,
+                                 priv->cr,
+                                 color,
+                                 priv->stipple[part],
+                                 priv->gc_changed);
        }
 
-      return priv->gc;
+      priv->last_part = part;
+      priv->gc_changed = FALSE;
     }
+
+  return priv->cr;
 }
 
 static void
@@ -289,86 +233,24 @@ gdk_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
 {
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+  cairo_t *cr;
 
-  flush_trapezoids (gdk_renderer);
+  cr = get_cairo_context (gdk_renderer, 
+                         PANGO_RENDER_PART_FOREGROUND);
 
-  if (!priv->in_emboss && priv->embossed)
+  if (priv->embossed)
     {
-      PangoMatrix *save_matrix;
-      PangoColor *save_color;
-
-      emboss_renderer (renderer, PANGO_RENDER_PART_FOREGROUND, &save_matrix, &save_color);
-      gdk_draw_glyphs_transformed (priv->drawable,
-                                  get_gc (gdk_renderer, PANGO_RENDER_PART_FOREGROUND),
-                                  renderer->matrix, font, x, y, glyphs);
-      unemboss_renderer (renderer, PANGO_RENDER_PART_FOREGROUND, &save_matrix, &save_color);
+      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);
     }
 
-  gdk_draw_glyphs_transformed (priv->drawable,
-                              get_gc (gdk_renderer, PANGO_RENDER_PART_FOREGROUND),
-                              renderer->matrix, font, x, y, glyphs);
-}
-
-/* Outputs any pending trapezoids, we do this when the part or
- * part color changes, when we are about to draw text, etc. */
-static void
-flush_trapezoids (GdkPangoRenderer *gdk_renderer)
-{
-  GdkPangoRendererPrivate *priv = gdk_renderer->priv;
-
-  if (!priv->trapezoids || priv->trapezoids->len == 0)
-    return;
-
-  gdk_draw_trapezoids (priv->drawable,
-                      get_gc (gdk_renderer, priv->trapezoid_part),
-                      (GdkTrapezoid *)priv->trapezoids->data,
-                      priv->trapezoids->len);
-
-  g_array_set_size (priv->trapezoids, 0);
-}
-
-/* Draws a single trapezoid ... we don't draw it immediately, but rather
- * cache it to join together with other trapezoids that form part of the
- * same logical shape */
-static void
-gdk_pango_renderer_draw_trapezoid (PangoRenderer   *renderer,
-                                  PangoRenderPart  part,
-                                  double           y1,
-                                  double           x11,
-                                  double           x21,
-                                  double           y2,
-                                  double           x12,
-                                  double           x22)
-{
-  GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
-  GdkTrapezoid trap;
-
-  if (!gdk_renderer->priv->trapezoids)
-    gdk_renderer->priv->trapezoids = g_array_new (FALSE, FALSE,
-                                                 sizeof (GdkTrapezoid));
-  
-  if (gdk_renderer->priv->trapezoids->len > 0 &&
-      gdk_renderer->priv->trapezoid_part != part)
-    flush_trapezoids (gdk_renderer);
-  
-  gdk_renderer->priv->trapezoid_part = part;
-
-  trap.y1 = y1;
-  trap.x11 = x11;
-  trap.x21 = x21;
-  trap.y2 = y2;
-  trap.x12 = x12;
-  trap.x22 = x22;
-
-  g_array_append_val (gdk_renderer->priv->trapezoids, trap);
+  cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
+  pango_cairo_show_glyph_string (cr, font, glyphs);
 }
 
-/* We can't handle embossing at the level of trapezoids, because when an
- * underline is split into multiple trapezoids, the normal and shadow
- * trapezoids will be drawn mixed together. Instead, we have to emboss
- * and entire rectangle or error underline
- */
-
 static void
 gdk_pango_renderer_draw_rectangle (PangoRenderer    *renderer,
                                   PangoRenderPart   part,
@@ -379,20 +261,26 @@ gdk_pango_renderer_draw_rectangle (PangoRenderer    *renderer,
 {
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+  cairo_t *cr;
+  
+  cr = get_cairo_context (gdk_renderer, part);
 
-  if (!priv->in_emboss && priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
+  if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
     {
-      PangoMatrix *save_matrix;
-      PangoColor *save_color;
-
-      emboss_renderer (renderer, part, &save_matrix, &save_color);
-      PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_rectangle (renderer, part,
-                                                                             x, y, width, height);
-      unemboss_renderer (renderer, part, &save_matrix, &save_color);
+      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);
     }
 
-  PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_rectangle (renderer, part,
-                                                                         x, y, width, height);
+  cairo_rectangle (cr,
+                  (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+                  (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+  cairo_fill (cr);
 }
 
 static void
@@ -404,20 +292,23 @@ gdk_pango_renderer_draw_error_underline (PangoRenderer    *renderer,
 {
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
-
-  if (!priv->in_emboss && priv->embossed)
+  cairo_t *cr;
+  
+  cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
+  
+  if (priv->embossed)
     {
-      PangoMatrix *save_matrix;
-      PangoColor *save_color;
-
-      emboss_renderer (renderer, PANGO_RENDER_PART_UNDERLINE, &save_matrix, &save_color);
-      PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_error_underline (renderer,
-                                                                                   x, y, width, height);
-      unemboss_renderer (renderer, PANGO_RENDER_PART_UNDERLINE, &save_matrix, &save_color);
+      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_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_error_underline (renderer,
-                                                                               x, y, width, height);
+  pango_cairo_show_error_underline (cr,
+       (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+       (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
 }
 
 static void
@@ -426,16 +317,17 @@ gdk_pango_renderer_part_changed (PangoRenderer   *renderer,
 {
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
 
-  if (part == gdk_renderer->priv->trapezoid_part)
-    flush_trapezoids (gdk_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);
-
-  if (!gdk_renderer->priv->drawable || !gdk_renderer->priv->base_gc)
+  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");
@@ -446,8 +338,14 @@ static void
 gdk_pango_renderer_end (PangoRenderer *renderer)
 {
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
+  GdkPangoRendererPrivate *priv = gdk_renderer->priv;
 
-  flush_trapezoids (gdk_renderer);
+  if (priv->cr)
+    {
+      cairo_destroy (priv->cr);
+      priv->cr = NULL;
+    }
+  priv->last_part = (PangoRenderPart)-1;
 }
 
 static void
@@ -457,12 +355,15 @@ gdk_pango_renderer_prepare_run (PangoRenderer  *renderer,
   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
   gboolean embossed = FALSE;
   GdkBitmap *stipple = NULL;
+  gboolean changed = FALSE;
+  PangoColor emboss_color;
   GSList *l;
   int i;
-  
-  embossed = FALSE;
-  stipple = NULL;
-  
+
+  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;
@@ -479,6 +380,10 @@ gdk_pango_renderer_prepare_run (PangoRenderer  *renderer,
        {
          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);
@@ -489,9 +394,18 @@ gdk_pango_renderer_prepare_run (PangoRenderer  *renderer,
   if (embossed != gdk_renderer->priv->embossed)
     {
       gdk_renderer->priv->embossed = embossed;
-      pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
+      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++)
@@ -545,6 +459,9 @@ 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
@@ -555,7 +472,6 @@ gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
   PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
   
   renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
-  renderer_class->draw_trapezoid = gdk_pango_renderer_draw_trapezoid;
   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;
@@ -574,7 +490,9 @@ gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
                                                         P_("Screen"),
                                                         P_("the GdkScreen for the renderer"),
                                                         GDK_TYPE_SCREEN,
-                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+                                                        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));  
 }
@@ -603,12 +521,14 @@ gdk_pango_renderer_new (GdkScreen *screen)
 
 static void
 on_renderer_display_closed (GdkDisplay       *display,
+                            gboolean          is_error,
                            GdkPangoRenderer *renderer)
 {
-  g_signal_handlers_disconnect_by_func (renderer->priv->screen,
-                                       (gpointer)on_renderer_display_closed,
+  g_signal_handlers_disconnect_by_func (display,
+                                       on_renderer_display_closed,
                                        renderer);
-  g_object_set_data (G_OBJECT (renderer->priv->screen), "gdk-pango-renderer", NULL);
+  g_object_set_data (G_OBJECT (renderer->priv->screen),
+                     g_intern_static_string ("gdk-pango-renderer"), NULL);
 }
 
 /**
@@ -621,7 +541,7 @@ on_renderer_display_closed (GdkDisplay       *display,
  * 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_drawable() to set the drawable and graphics context
+ * 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
@@ -641,7 +561,8 @@ gdk_pango_renderer_get_default (GdkScreen *screen)
   if (!renderer)
     {
       renderer = gdk_pango_renderer_new (screen);
-      g_object_set_data_full (G_OBJECT (screen), "gdk-pango-renderer", renderer,
+      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",
@@ -671,8 +592,6 @@ gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
 
   priv = gdk_renderer->priv;
   
-  flush_trapezoids (gdk_renderer);
-
   if (priv->drawable != drawable)
     {
       if (priv->drawable)
@@ -707,8 +626,6 @@ gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
 
   priv = gdk_renderer->priv;
   
-  flush_trapezoids (gdk_renderer);
-
   if (priv->base_gc != gc)
     {
       if (priv->base_gc)
@@ -717,19 +634,7 @@ gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
       if (priv->base_gc)
        g_object_ref (priv->base_gc);
 
-      if (priv->gc)
-       {
-         g_object_unref (priv->gc);
-         priv->gc = NULL;
-       }
-      
-      priv->gc_color_set = FALSE;
-
-      if (priv->gc_stipple)
-       {
-         g_object_unref (priv->gc_stipple);
-         priv->gc_stipple = NULL;
-       }
+      priv->gc_changed = TRUE;
     }
 }
 
@@ -939,8 +844,22 @@ gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
       PangoMatrix tmp_matrix;
       
       tmp_matrix = *matrix;
-      tmp_matrix.x0 = x;
-      tmp_matrix.y0 = y;
+      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;
@@ -954,55 +873,6 @@ gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
   release_renderer (renderer);
 }
 
-/* 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;
-
-  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++)
-       {
-         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;
-         
-         if (i == 0 && j == 0)
-           {
-             x_min = x_max = xt;
-             y_min = y_max = yt;
-           }
-         else
-           {
-             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;
-           }
-       }
-    }
-  
-  rect->x = floor (x_min);
-  rect->width = ceil (x_max) - rect->x;
-  rect->y = floor (y_min);
-  rect->height = floor (y_max) - rect->y;
-}
-
 /**
  * gdk_draw_layout_with_colors:
  * @drawable:  the drawable on which to draw string
@@ -1051,21 +921,33 @@ gdk_draw_layout_with_colors (GdkDrawable     *drawable,
   if (matrix)
     {
       PangoMatrix tmp_matrix;
-      GdkRectangle rect;
+      PangoRectangle rect;
 
-      get_rotated_layout_bounds (layout, &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);
@@ -1131,6 +1013,8 @@ gdk_draw_layout (GdkDrawable     *drawable,
   gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
 }
 
+/* GdkPangoAttrStipple */
+
 static PangoAttribute *
 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
 {
@@ -1197,6 +1081,8 @@ gdk_pango_attr_stipple_new (GdkBitmap *stipple)
   return (PangoAttribute *)result;
 }
 
+/* GdkPangoAttrEmbossed */
+
 static PangoAttribute *
 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
 {
@@ -1223,10 +1109,9 @@ gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
 
 /**
  * gdk_pango_attr_embossed_new:
- * @embossed: a bitmap to be set as embossed
+ * @embossed: if the region should be embossed
  *
- * Creates a new attribute containing a embossed bitmap to be used when
- * rendering the text.
+ * Creates a new attribute flagging a region as embossed or not.
  *
  * Return value: new #PangoAttribute
  **/
@@ -1254,11 +1139,134 @@ gdk_pango_attr_embossed_new (gboolean 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
+ *
+ * Creates a new attribute specifying the color to emboss text with.
+ *
+ * Return value: new #PangoAttribute
+ *
+ * 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;
+}
+
 /* Get a clip region to draw only part of a layout. index_ranges
  * contains alternating range starts/stops. The region is the
  * region which contains the given ranges, i.e. if you draw with the
  * region as clip, only the given ranges are drawn.
  */
+static GdkRegion*
+layout_iter_get_line_clip_region (PangoLayoutIter *iter,
+                                 gint             x_origin,
+                                 gint             y_origin,
+                                 gint            *index_ranges,
+                                 gint             n_ranges)
+{
+  PangoLayoutLine *line;
+  GdkRegion *clip_region;
+  PangoRectangle logical_rect;
+  gint baseline;
+  gint i;
+
+  line = pango_layout_iter_get_line_readonly (iter);
+
+  clip_region = gdk_region_new ();
+
+  pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+  baseline = pango_layout_iter_get_baseline (iter);
+
+  i = 0;
+  while (i < n_ranges)
+    {  
+      gint *pixel_ranges = NULL;
+      gint n_pixel_ranges = 0;
+      gint j;
+
+      /* Note that get_x_ranges returns layout coordinates
+       */
+      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++)
+        {
+          GdkRectangle rect;
+         int x_off, y_off;
+          
+          x_off = PANGO_PIXELS (pixel_ranges[2*j] - logical_rect.x);
+         y_off = PANGO_PIXELS (baseline - logical_rect.y);
+
+          rect.x = x_origin + x_off;
+          rect.y = y_origin - y_off;
+          rect.width = PANGO_PIXELS (pixel_ranges[2*j + 1] - logical_rect.x) - x_off;
+          rect.height = PANGO_PIXELS (baseline - logical_rect.y + logical_rect.height) - y_off;
+
+          gdk_region_union_with_rect (clip_region, &rect);
+        }
+
+      g_free (pixel_ranges);
+      ++i;
+    }
+  return clip_region;
+}
 
 /**
  * gdk_pango_layout_line_get_clip_region:
@@ -1277,6 +1285,11 @@ gdk_pango_attr_embossed_new (gboolean embossed)
  * contained inside the line. This is to draw the selection all the way
  * to the side of the layout. However, the clip region is in line coordinates,
  * not layout coordinates.
+ *
+ * Note that the regions returned correspond to logical extents of the text
+ * ranges, not ink extents. So the drawn line may in fact touch areas out of
+ * the clip region.  The clip region is mainly useful for highlightling parts
+ * of text, such as when text is selected.
  * 
  * Return value: a clip region containing the given ranges
  **/
@@ -1288,54 +1301,18 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
                                        gint             n_ranges)
 {
   GdkRegion *clip_region;
-  gint i;
-  PangoRectangle logical_rect;
   PangoLayoutIter *iter;
-  gint baseline;
   
   g_return_val_if_fail (line != NULL, NULL);
   g_return_val_if_fail (index_ranges != NULL, NULL);
   
-  clip_region = gdk_region_new ();
-
   iter = pango_layout_get_iter (line->layout);
-  while (pango_layout_iter_get_line (iter) != line)
+  while (pango_layout_iter_get_line_readonly (iter) != line)
     pango_layout_iter_next_line (iter);
   
-  pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
-  baseline = pango_layout_iter_get_baseline (iter);
-  
-  pango_layout_iter_free (iter);
-  
-  i = 0;
-  while (i < n_ranges)
-    {  
-      gint *pixel_ranges = NULL;
-      gint n_pixel_ranges = 0;
-      gint j;
-
-      /* 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);
-  
-      for (j=0; j < n_pixel_ranges; j++)
-        {
-          GdkRectangle rect;
-          
-          rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
-          rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
-          rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
-          rect.height = logical_rect.height / PANGO_SCALE;
-          
-          gdk_region_union_with_rect (clip_region, &rect);
-        }
+  clip_region = layout_iter_get_line_clip_region(iter, x_origin, y_origin, index_ranges, n_ranges);
 
-      g_free (pixel_ranges);
-      ++i;
-    }
+  pango_layout_iter_free (iter);
 
   return clip_region;
 }
@@ -1353,6 +1330,11 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
  * you would pass to gdk_draw_layout_line(). @index_ranges should contain
  * ranges of bytes in the layout's text.
  * 
+ * Note that the regions returned correspond to logical extents of the text
+ * ranges, not ink extents. So the drawn layout may in fact touch areas out of
+ * the clip region.  The clip region is mainly useful for highlightling parts
+ * of text, such as when text is selected.
+ * 
  * Return value: a clip region containing the given ranges
  **/
 GdkRegion*
@@ -1375,20 +1357,17 @@ gdk_pango_layout_get_clip_region (PangoLayout *layout,
   do
     {
       PangoRectangle logical_rect;
-      PangoLayoutLine *line;
       GdkRegion *line_region;
       gint baseline;
       
-      line = pango_layout_iter_get_line (iter);      
-
       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
       baseline = pango_layout_iter_get_baseline (iter);      
 
-      line_region = gdk_pango_layout_line_get_clip_region (line,
-                                                           x_origin + logical_rect.x / PANGO_SCALE,
-                                                           y_origin + baseline / PANGO_SCALE,
-                                                           index_ranges,
-                                                           n_ranges);
+      line_region = layout_iter_get_line_clip_region(iter, 
+                                                    x_origin + PANGO_PIXELS (logical_rect.x),
+                                                    y_origin + PANGO_PIXELS (baseline),
+                                                    index_ranges,
+                                                    n_ranges);
 
       gdk_region_union (clip_region, line_region);
       gdk_region_destroy (line_region);
@@ -1411,6 +1390,12 @@ gdk_pango_layout_get_clip_region (PangoLayout *layout,
  * instead of this function, to get the appropriate context for
  * the widget you intend to render text onto.
  * 
+ * The newly created context will have the default font options (see
+ * #cairo_font_options_t) for the default screen; if these options
+ * change it will not be updated. Using gtk_widget_get_pango_context()
+ * 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
  **/
 PangoContext *
@@ -1419,5 +1404,50 @@ 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.
+ * 
+ * The newly created context will have the default font options
+ * (see #cairo_font_options_t) for the screen; if these options
+ * change it will not be updated. Using gtk_widget_get_pango_context()
+ * 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
+ *
+ * Since: 2.2
+ **/
+PangoContext *
+gdk_pango_context_get_for_screen (GdkScreen *screen)
+{
+  PangoFontMap *fontmap;
+  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));
+
+  options = gdk_screen_get_font_options (screen);
+  pango_cairo_context_set_font_options (context, options);
+
+  dpi = gdk_screen_get_resolution (screen);
+  pango_cairo_context_set_resolution (context, dpi);
+
+  return context;
+}
+
 #define __GDK_PANGO_C__
 #include "gdkaliasdef.c"