]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkpango.c
Revert name change
[~andy/gtk] / gdk / gdkpango.c
index 52dcfebd4166c798204ab4ddd4e7a6a0544d4677..0a484b535e44bcb31add27b6973c4b196b28af92 100644 (file)
@@ -17,7 +17,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
+#include "config.h"
 #include <math.h>
 #include <pango/pangocairo.h>
 #include "gdkcairo.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
@@ -50,6 +48,7 @@ struct _GdkPangoRendererPrivate
   gboolean override_color_set[MAX_RENDER_PART + 1];
   
   GdkBitmap *stipple[MAX_RENDER_PART + 1];
+  PangoColor emboss_color;
   gboolean embossed;
 
   cairo_t *cr;
@@ -58,10 +57,13 @@ struct _GdkPangoRendererPrivate
   /* 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,
@@ -115,9 +117,11 @@ gdk_pango_renderer_constructor (GType                  type,
 /* Adjusts matrix and color for the renderer to draw the secondary
  * "shadow" copy for embossed text */
 static void
-emboss_context (cairo_t *cr)
+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,
@@ -128,7 +132,26 @@ emboss_context (cairo_t *cr)
   tmp_matrix.y0 += 1.0;
   cairo_set_matrix (cr, &tmp_matrix);
 
-  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  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 *
@@ -156,28 +179,46 @@ get_cairo_context (GdkPangoRenderer *gdk_renderer,
          cairo_set_matrix (priv->cr, &cairo_matrix);
        }
     }
-  
-  priv->last_part = (PangoRenderPart)-1;
+
   if (part != priv->last_part)
     {
-      PangoColor *pango_color = pango_renderer_get_color (renderer,
-                                                         part);
-      GdkColor *color = NULL;
+      PangoColor *pango_color;
+      GdkColor *color;
       GdkColor tmp_color;
-      if (pango_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)
        {
-         tmp_color.red = pango_color->red;
-         tmp_color.green = pango_color->green;
-         tmp_color.blue = pango_color->blue;
-         
-         color = &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;
+           }
+         else
+           color = NULL;
+
+         _gdk_gc_update_context (priv->base_gc,
+                                 priv->cr,
+                                 color,
+                                 priv->stipple[part],
+                                 priv->gc_changed);
        }
 
-      _gdk_gc_update_context (priv->base_gc,
-                             priv->cr,
-                             color,
-                             priv->stipple[part]);
       priv->last_part = part;
+      priv->gc_changed = FALSE;
     }
 
   return priv->cr;
@@ -200,92 +241,14 @@ gdk_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
   if (priv->embossed)
     {
       cairo_save (cr);
-      emboss_context (cr);
-      cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
+      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, x / PANGO_SCALE, y / PANGO_SCALE);
-  pango_cairo_show_glyph_string (cr, font, glyphs);
-}
-
-/* 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 */
-    }
-  
-  /* Top of squiggle */
-  for (i -= 2; i >= 0; i -= 2)
-    {
-      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 */
-      }
-      
-      cairo_line_to (cr, x_left, y_top);   /* H */
-    }
 
-  cairo_close_path (cr);
-  cairo_fill (cr);
+  cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
+  pango_cairo_show_glyph_string (cr, font, glyphs);
 }
 
 static void
@@ -305,7 +268,7 @@ gdk_pango_renderer_draw_rectangle (PangoRenderer    *renderer,
   if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
     {
       cairo_save (cr);
-      emboss_context (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);
@@ -336,16 +299,16 @@ gdk_pango_renderer_draw_error_underline (PangoRenderer    *renderer,
   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);
+      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);
     }
 
-  draw_error_underline (cr,
-                       (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
-                       (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+  pango_cairo_show_error_underline (cr,
+       (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+       (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
 }
 
 static void
@@ -392,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;
@@ -414,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);
@@ -424,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++)
@@ -482,6 +461,7 @@ gdk_pango_renderer_init (GdkPangoRenderer *renderer)
                                                GdkPangoRendererPrivate);
 
   renderer->priv->last_part = (PangoRenderPart)-1;
+  renderer->priv->gc_changed = TRUE;
 }
 
 static void
@@ -541,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);
 }
 
 /**
@@ -579,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",
@@ -650,6 +633,8 @@ gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
       priv->base_gc = gc;
       if (priv->base_gc)
        g_object_ref (priv->base_gc);
+
+      priv->gc_changed = TRUE;
     }
 }
 
@@ -859,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;
@@ -874,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
@@ -971,15 +921,27 @@ 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;
     }
@@ -1051,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)
 {
@@ -1117,6 +1081,8 @@ gdk_pango_attr_stipple_new (GdkBitmap *stipple)
   return (PangoAttribute *)result;
 }
 
+/* GdkPangoAttrEmbossed */
+
 static PangoAttribute *
 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
 {
@@ -1143,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
  **/
@@ -1174,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,
+                                 const 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:
@@ -1197,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
  **/
@@ -1204,60 +1297,22 @@ GdkRegion*
 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
                                        gint             x_origin,
                                        gint             y_origin,
-                                       gint            *index_ranges,
+                                       const gint      *index_ranges,
                                        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
-       */
-      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;
-          
-          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;
 }
@@ -1275,13 +1330,18 @@ 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*
 gdk_pango_layout_get_clip_region (PangoLayout *layout,
                                   gint         x_origin,
                                   gint         y_origin,
-                                  gint        *index_ranges,
+                                  const gint  *index_ranges,
                                   gint         n_ranges)
 {
   PangoLayoutIter *iter;  
@@ -1297,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);
@@ -1333,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 *
@@ -1353,6 +1416,12 @@ gdk_pango_context_get (void)
  * 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
@@ -1361,12 +1430,23 @@ 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 ();
   
-  return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
+  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__