]> Pileus Git - ~andy/gtk/blob - gdk/gdkpango.c
add _gtk_tree_view_column_get_editable_cell and
[~andy/gtk] / gdk / gdkpango.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2000 Red Hat, Inc. 
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gdkcolor.h"
21 #include "gdkgc.h"
22 #include "gdkpango.h"
23 #include "gdkrgb.h"
24 #include "gdkprivate.h"
25
26 #define GDK_INFO_KEY "gdk-info"
27
28 typedef struct _GdkPangoContextInfo GdkPangoContextInfo;
29
30 struct _GdkPangoContextInfo
31 {
32   GdkColormap *colormap;
33 };
34
35 static PangoAttrType gdk_pango_attr_stipple_type;
36 static PangoAttrType gdk_pango_attr_embossed_type;
37
38 static void gdk_pango_get_item_properties (PangoItem      *item,
39                                            PangoUnderline *uline,
40                                            gboolean       *strikethrough,
41                                            gint           *rise,
42                                            PangoColor     *fg_color,
43                                            gboolean       *fg_set,
44                                            PangoColor     *bg_color,
45                                            gboolean       *bg_set,
46                                            gboolean       *embossed,
47                                            GdkBitmap     **stipple,
48                                            gboolean       *shape_set,
49                                            PangoRectangle *ink_rect,
50                                            PangoRectangle *logical_rect);
51
52 static void
53 gdk_pango_context_destroy (GdkPangoContextInfo *info)
54 {
55   if (info->colormap)
56     gdk_colormap_unref (info->colormap);
57   g_free (info);
58 }
59
60 static GdkPangoContextInfo *
61 gdk_pango_context_get_info (PangoContext *context, gboolean create)
62 {
63   GdkPangoContextInfo *info =
64     g_object_get_qdata (G_OBJECT (context),
65                         g_quark_try_string (GDK_INFO_KEY));
66   if (!info && create)
67     {
68       info = g_new (GdkPangoContextInfo, 1);
69       info->colormap = NULL;
70
71       g_object_set_qdata_full (G_OBJECT (context),
72                                g_quark_from_static_string (GDK_INFO_KEY),
73                                info, (GDestroyNotify)gdk_pango_context_destroy);
74     }
75
76   return info;
77 }
78
79 static GdkGC *
80 gdk_pango_get_gc (GdkDrawable    *drawable,
81                   PangoContext   *context,
82                   PangoColor     *fg_color,
83                   GdkBitmap      *stipple,
84                   GdkGC          *base_gc)
85 {
86   GdkGC *result;
87   GdkPangoContextInfo *info;
88   
89   g_return_val_if_fail (context != NULL, NULL);
90
91   info = gdk_pango_context_get_info (context, FALSE);
92
93   if (info == NULL || info->colormap == NULL)
94     {
95       g_warning ("you must set the colormap on a PangoContext before using it to draw a layout");
96       return NULL;
97     }
98
99   result = gdk_gc_new (drawable);
100   gdk_gc_copy (result, base_gc);
101   
102   if (fg_color)
103     {
104       GdkColor color;
105       
106       color.red = fg_color->red;
107       color.green = fg_color->green;
108       color.blue = fg_color->blue;
109
110       gdk_rgb_find_color (info->colormap, &color);
111       gdk_gc_set_foreground (result, &color);
112     }
113
114   if (stipple)
115     {
116       gdk_gc_set_fill (result, GDK_STIPPLED);
117       gdk_gc_set_stipple (result, stipple);
118     }
119   
120   return result;
121 }
122
123 static void
124 gdk_pango_free_gc (PangoContext *context,
125                    GdkGC        *gc)
126 {
127   gdk_gc_unref (gc);
128 }
129
130 /**
131  * gdk_pango_context_set_colormap:
132  * @context: a #PangoContext
133  * @colormap: a #GdkColormap
134  *
135  * Sets the colormap to be used for drawing with @context.
136  * If you obtained your context from gtk_widget_get_pango_context() or
137  * gtk_widget_create_pango_context(), the colormap will already be set
138  * to the colormap for the widget, so you shouldn't need this
139  * function.
140  * 
141  **/
142 void
143 gdk_pango_context_set_colormap (PangoContext *context,
144                                 GdkColormap  *colormap)
145 {
146   GdkPangoContextInfo *info;
147   
148   g_return_if_fail (context != NULL);
149
150   info = gdk_pango_context_get_info (context, TRUE);
151   g_return_if_fail (info != NULL);
152   
153   if (info->colormap != colormap)
154     {
155       if (info->colormap)
156         gdk_colormap_unref (info->colormap);
157
158       info->colormap = colormap;
159       
160       if (info->colormap)
161         gdk_colormap_ref (info->colormap);
162     }
163 }
164
165 /**
166  * gdk_draw_layout_line_with_colors:
167  * @drawable:  the drawable on which to draw the line
168  * @gc:        base graphics to use
169  * @x:         the x position of start of string (in pixels)
170  * @y:         the y position of baseline (in pixels)
171  * @line:      a #PangoLayoutLine
172  * @foreground: foreground override color, or %NULL for none
173  * @background: background override color, or %NULL for none
174  *
175  * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
176  * layout's normal colors with @foreground and/or @background.
177  * @foreground and @background need not be allocated.
178  */
179 void 
180 gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
181                                   GdkGC            *gc,
182                                   gint              x, 
183                                   gint              y,
184                                   PangoLayoutLine  *line,
185                                   GdkColor         *foreground,
186                                   GdkColor         *background)
187 {
188   GSList *tmp_list = line->runs;
189   PangoRectangle overall_rect;
190   PangoRectangle logical_rect;
191   PangoRectangle ink_rect;
192   PangoContext *context;
193   gint x_off = 0;
194   gint rise = 0;
195   gboolean embossed;
196   GdkBitmap *stipple;
197
198   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
199   g_return_if_fail (GDK_IS_GC (gc));
200   g_return_if_fail (line != NULL);
201
202   context = pango_layout_get_context (line->layout);
203   
204   pango_layout_line_get_extents (line,NULL, &overall_rect);
205   
206   while (tmp_list)
207     {
208       PangoUnderline uline = PANGO_UNDERLINE_NONE;
209       PangoLayoutRun *run = tmp_list->data;
210       PangoColor fg_color, bg_color;
211       gboolean strike, fg_set, bg_set, shape_set;
212       GdkGC *fg_gc;
213       gint risen_y;
214       
215       tmp_list = tmp_list->next;
216       
217       gdk_pango_get_item_properties (run->item, &uline,
218                                      &strike,
219                                      &rise,
220                                      &fg_color, &fg_set,
221                                      &bg_color, &bg_set,
222                                      &embossed,
223                                      &stipple,
224                                      &shape_set,
225                                      &ink_rect,
226                                      &logical_rect);
227
228       /* we subtract the rise because X coordinates are upside down */
229       risen_y = y - rise / PANGO_SCALE;
230       
231       if (!shape_set)
232         {
233           if (uline == PANGO_UNDERLINE_NONE)
234             pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
235                                         NULL, &logical_rect);
236           else
237             pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
238                                         &ink_rect, &logical_rect);
239         }
240
241       if (bg_set || background)
242         {
243           GdkGC *bg_gc;
244           PangoColor tmp = bg_color;
245           
246           if (background)
247             {
248               tmp.red = background->red;
249               tmp.blue = background->blue;
250               tmp.green = background->green;
251             }
252           
253           bg_gc = gdk_pango_get_gc (drawable, context, &tmp, stipple, gc);
254           
255           gdk_draw_rectangle (drawable, bg_gc, TRUE,
256                               x + (x_off + logical_rect.x) / PANGO_SCALE,
257                               risen_y + overall_rect.y / PANGO_SCALE,
258                               logical_rect.width / PANGO_SCALE,
259                               overall_rect.height / PANGO_SCALE);
260
261           if (stipple)
262             gdk_gc_set_fill (bg_gc, GDK_SOLID);
263           
264           gdk_pango_free_gc (context, bg_gc);
265         }
266
267       if (fg_set || stipple || foreground)
268         {
269           PangoColor tmp = fg_color;
270           
271           if (foreground)
272             {
273               tmp.red = foreground->red;
274               tmp.blue = foreground->blue;
275               tmp.green = foreground->green;
276             }
277           
278           fg_gc = gdk_pango_get_gc (drawable, context, fg_set ? &tmp : NULL,
279                                     stipple, gc);
280         }
281       else
282         fg_gc = gc;
283       
284       if (!shape_set)
285         {
286           gint gx, gy;
287
288           gx = x + x_off / PANGO_SCALE;
289           gy = risen_y;
290           
291           if (embossed)
292             {
293               PangoColor color = { 65535, 65535, 65535 };
294               GdkGC *white_gc = gdk_pango_get_gc (drawable, context, &color, stipple, fg_gc);
295               gdk_draw_glyphs (drawable, white_gc, run->item->analysis.font,
296                                gx + 1,
297                                gy + 1,
298                                run->glyphs);
299               gdk_pango_free_gc (context, white_gc);
300             }
301           
302           gdk_draw_glyphs (drawable, fg_gc, run->item->analysis.font,
303                            gx, gy,
304                            run->glyphs);
305         }
306       
307       switch (uline)
308         {
309         case PANGO_UNDERLINE_NONE:
310           break;
311         case PANGO_UNDERLINE_DOUBLE:
312           gdk_draw_line (drawable, fg_gc,
313                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
314                          risen_y + 3,
315                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
316                          risen_y + 3);
317           /* Fall through */
318         case PANGO_UNDERLINE_SINGLE:
319           gdk_draw_line (drawable, fg_gc,
320                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
321                          risen_y + 1,
322                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
323                          risen_y + 1);
324           break;
325         case PANGO_UNDERLINE_LOW:
326           gdk_draw_line (drawable, fg_gc,
327                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
328                          risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 1,
329                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
330                          risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 1);
331           break;
332         }
333
334       if (strike)
335       {
336           int centerline = logical_rect.y + logical_rect.height / 2;
337           
338           gdk_draw_line (drawable, fg_gc,
339                          x + (x_off + logical_rect.x) / PANGO_SCALE - 1,
340                          risen_y + centerline / PANGO_SCALE,
341                          x + (x_off + logical_rect.x + logical_rect.width) / PANGO_SCALE + 1,
342                          risen_y + centerline / PANGO_SCALE);
343       }
344       
345       if (fg_gc != gc)
346         gdk_pango_free_gc (context, fg_gc);
347
348       x_off += logical_rect.width;
349     }
350 }
351
352 /**
353  * gdk_draw_layout_with_colors:
354  * @drawable:  the drawable on which to draw string
355  * @gc:        base graphics context to use
356  * @x:         the X position of the left of the layout (in pixels)
357  * @y:         the Y position of the top of the layout (in pixels)
358  * @layout:    a #PangoLayout
359  * @foreground: foreground override color, or %NULL for none
360  * @background: background override color, or %NULL for none
361  *
362  * Render a #PangoLayout onto a #GdkDrawable, overriding the
363  * layout's normal colors with @foreground and/or @background.
364  * @foreground and @background need not be allocated.
365  */
366 void 
367 gdk_draw_layout_with_colors (GdkDrawable     *drawable,
368                              GdkGC           *gc,
369                              int              x, 
370                              int              y,
371                              PangoLayout     *layout,
372                              GdkColor        *foreground,
373                              GdkColor        *background)
374 {
375   PangoLayoutIter *iter;
376   
377   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
378   g_return_if_fail (GDK_IS_GC (gc));
379   g_return_if_fail (PANGO_IS_LAYOUT (layout));
380
381   iter = pango_layout_get_iter (layout);
382   
383   do
384     {
385       PangoRectangle logical_rect;
386       PangoLayoutLine *line;
387       int baseline;
388       
389       line = pango_layout_iter_get_line (iter);
390       
391       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
392       baseline = pango_layout_iter_get_baseline (iter);
393       
394       gdk_draw_layout_line_with_colors (drawable, gc,
395                                         x + logical_rect.x / PANGO_SCALE,
396                                         y + baseline / PANGO_SCALE,
397                                         line,
398                                         foreground,
399                                         background);
400     }
401   while (pango_layout_iter_next_line (iter));
402
403   pango_layout_iter_free (iter);
404 }
405
406 /**
407  * gdk_draw_layout_line:
408  * @drawable:  the drawable on which to draw the line
409  * @gc:        base graphics to use
410  * @x:         the x position of start of string (in pixels)
411  * @y:         the y position of baseline (in pixels)
412  * @line:      a #PangoLayoutLine
413  *
414  * Render a #PangoLayoutLine onto an GDK drawable
415  */
416 void 
417 gdk_draw_layout_line (GdkDrawable      *drawable,
418                       GdkGC            *gc,
419                       gint              x, 
420                       gint              y,
421                       PangoLayoutLine  *line)
422 {
423   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
424   g_return_if_fail (GDK_IS_GC (gc));
425   g_return_if_fail (line != NULL);
426   
427   gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
428 }
429
430 /**
431  * gdk_draw_layout:
432  * @drawable:  the drawable on which to draw string
433  * @gc:        base graphics context to use
434  * @x:         the X position of the left of the layout (in pixels)
435  * @y:         the Y position of the top of the layout (in pixels)
436  * @layout:    a #PangoLayout
437  *
438  * Render a #PangoLayout onto a GDK drawable
439  */
440 void 
441 gdk_draw_layout (GdkDrawable     *drawable,
442                  GdkGC           *gc,
443                  int              x, 
444                  int              y,
445                  PangoLayout     *layout)
446 {
447   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
448   g_return_if_fail (GDK_IS_GC (gc));
449   g_return_if_fail (PANGO_IS_LAYOUT (layout));
450
451   gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
452 }
453
454 static void
455 gdk_pango_get_item_properties (PangoItem      *item,
456                                PangoUnderline *uline,
457                                gboolean       *strikethrough,
458                                gint           *rise,
459                                PangoColor     *fg_color,
460                                gboolean       *fg_set,
461                                PangoColor     *bg_color,
462                                gboolean       *bg_set,
463                                gboolean       *embossed,
464                                GdkBitmap     **stipple,
465                                gboolean       *shape_set,
466                                PangoRectangle *ink_rect,
467                                PangoRectangle *logical_rect)
468 {
469   GSList *tmp_list = item->analysis.extra_attrs;
470
471   if (strikethrough)
472       *strikethrough = FALSE;
473   
474   if (fg_set)
475     *fg_set = FALSE;
476   
477   if (bg_set)
478     *bg_set = FALSE;
479
480   if (shape_set)
481     *shape_set = FALSE;
482
483   if (rise)
484     *rise = 0;
485
486   if (embossed)
487     *embossed = FALSE;
488
489   if (stipple)
490     *stipple = NULL;
491   
492   while (tmp_list)
493     {
494       PangoAttribute *attr = tmp_list->data;
495
496       switch (attr->klass->type)
497         {
498         case PANGO_ATTR_UNDERLINE:
499           if (uline)
500             *uline = ((PangoAttrInt *)attr)->value;
501           break;
502
503         case PANGO_ATTR_STRIKETHROUGH:
504             if (strikethrough)
505                 *strikethrough = ((PangoAttrInt *)attr)->value;
506             break;
507             
508         case PANGO_ATTR_FOREGROUND:
509           if (fg_color)
510             *fg_color = ((PangoAttrColor *)attr)->color;
511           if (fg_set)
512             *fg_set = TRUE;
513           
514           break;
515           
516         case PANGO_ATTR_BACKGROUND:
517           if (bg_color)
518             *bg_color = ((PangoAttrColor *)attr)->color;
519           if (bg_set)
520             *bg_set = TRUE;
521           
522           break;
523
524         case PANGO_ATTR_SHAPE:
525           if (shape_set)
526             *shape_set = TRUE;
527           if (logical_rect)
528             *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
529           if (ink_rect)
530             *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
531           break;
532
533         case PANGO_ATTR_RISE:
534           if (rise)
535             *rise = ((PangoAttrInt *)attr)->value;
536           break;
537           
538         default:
539           /* stipple_type and embossed_type aren't necessarily
540            * initialized, but they are 0, which is an
541            * invalid type so won't occur. 
542            */
543           if (stipple && attr->klass->type == gdk_pango_attr_stipple_type)
544             {
545               *stipple = ((GdkPangoAttrStipple*)attr)->stipple;
546             }
547           else if (embossed && attr->klass->type == gdk_pango_attr_embossed_type)
548             {
549               *embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
550             }
551           break;
552         }
553       tmp_list = tmp_list->next;
554     }
555 }
556
557
558 static PangoAttribute *
559 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
560 {
561   const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
562
563   return gdk_pango_attr_stipple_new (src->stipple);
564 }
565
566 static void
567 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
568 {
569   GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
570
571   if (st->stipple)
572     g_object_unref (G_OBJECT (st->stipple));
573   
574   g_free (attr);
575 }
576
577 static gboolean
578 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
579                                     const PangoAttribute *attr2)
580 {
581   const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
582   const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
583
584   return a->stipple == b->stipple;
585 }
586
587 /**
588  * gdk_pango_attr_stipple_new:
589  * @stipple: a bitmap to be set as stipple
590  *
591  * Creates a new attribute containing a stipple bitmap to be used when
592  * rendering the text.
593  *
594  * Return value: new #PangoAttribute
595  **/
596
597 PangoAttribute *
598 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
599 {
600   GdkPangoAttrStipple *result;
601   
602   static PangoAttrClass klass = {
603     0,
604     gdk_pango_attr_stipple_copy,
605     gdk_pango_attr_stipple_destroy,
606     gdk_pango_attr_stipple_compare
607   };
608
609   if (!klass.type)
610     klass.type = gdk_pango_attr_stipple_type =
611       pango_attr_type_register ("GdkPangoAttrStipple");
612
613   result = g_new (GdkPangoAttrStipple, 1);
614   result->attr.klass = &klass;
615
616   if (stipple)
617     g_object_ref (stipple);
618   
619   result->stipple = stipple;
620
621   return (PangoAttribute *)result;
622 }
623
624 static PangoAttribute *
625 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
626 {
627   const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
628
629   return gdk_pango_attr_embossed_new (e->embossed);
630 }
631
632 static void
633 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
634 {
635   g_free (attr);
636 }
637
638 static gboolean
639 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
640                                  const PangoAttribute *attr2)
641 {
642   const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
643   const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
644
645   return e1->embossed == e2->embossed;
646 }
647
648 /**
649  * gdk_pango_attr_embossed_new:
650  * @embossed: a bitmap to be set as embossed
651  *
652  * Creates a new attribute containing a embossed bitmap to be used when
653  * rendering the text.
654  *
655  * Return value: new #PangoAttribute
656  **/
657
658 PangoAttribute *
659 gdk_pango_attr_embossed_new (gboolean embossed)
660 {
661   GdkPangoAttrEmbossed *result;
662   
663   static PangoAttrClass klass = {
664     0,
665     gdk_pango_attr_embossed_copy,
666     gdk_pango_attr_embossed_destroy,
667     gdk_pango_attr_embossed_compare
668   };
669
670   if (!klass.type)
671     klass.type = gdk_pango_attr_embossed_type =
672       pango_attr_type_register ("GdkPangoAttrEmbossed");
673
674   result = g_new (GdkPangoAttrEmbossed, 1);
675   result->attr.klass = &klass;
676   result->embossed = embossed;
677   
678   return (PangoAttribute *)result;
679 }
680
681 /* Get a clip region to draw only part of a layout. index_ranges
682  * contains alternating range starts/stops. The region is the
683  * region which contains the given ranges, i.e. if you draw with the
684  * region as clip, only the given ranges are drawn.
685  */
686
687 /**
688  * gdk_pango_layout_line_get_clip_region:
689  * @line: a #PangoLayoutLine 
690  * @x_origin: X pixel where you intend to draw the layout line with this clip
691  * @y_origin: baseline pixel where you intend to draw the layout line with this clip
692  * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
693  * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
694  * 
695  * Obtains a clip region which contains the areas where the given
696  * ranges of text would be drawn. @x_origin and @y_origin are the same
697  * position you would pass to gdk_draw_layout_line(). @index_ranges
698  * should contain ranges of bytes in the layout's text. The clip
699  * region will include space to the left or right of the line (to the
700  * layout bounding box) if you have indexes above or below the indexes
701  * contained inside the line. This is to draw the selection all the way
702  * to the side of the layout. However, the clip region is in line coordinates,
703  * not layout coordinates.
704  * 
705  * Return value: a clip region containing the given ranges
706  **/
707 GdkRegion*
708 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
709                                        gint             x_origin,
710                                        gint             y_origin,
711                                        gint            *index_ranges,
712                                        gint             n_ranges)
713 {
714   GdkRegion *clip_region;
715   gint i;
716   PangoRectangle logical_rect;
717   PangoLayoutIter *iter;
718   gint baseline;
719   
720   g_return_val_if_fail (line != NULL, NULL);
721   g_return_val_if_fail (index_ranges != NULL, NULL);
722   
723   clip_region = gdk_region_new ();
724
725   iter = pango_layout_get_iter (line->layout);
726   while (pango_layout_iter_get_line (iter) != line)
727     pango_layout_iter_next_line (iter);
728   
729   pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
730   baseline = pango_layout_iter_get_baseline (iter);
731   
732   pango_layout_iter_free (iter);
733   
734   i = 0;
735   while (i < n_ranges)
736     {  
737       gint *pixel_ranges = NULL;
738       gint n_pixel_ranges = 0;
739       gint j;
740
741       /* Note that get_x_ranges returns layout coordinates
742        */
743       pango_layout_line_get_x_ranges (line,
744                                       index_ranges[i*2],
745                                       index_ranges[i*2+1],
746                                       &pixel_ranges, &n_pixel_ranges);
747   
748       for (j=0; j < n_pixel_ranges; j++)
749         {
750           GdkRectangle rect;
751           
752           rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
753           rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
754           rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
755           rect.height = logical_rect.height / PANGO_SCALE;
756           
757           gdk_region_union_with_rect (clip_region, &rect);
758         }
759
760       g_free (pixel_ranges);
761       ++i;
762     }
763
764   return clip_region;
765 }
766
767 /**
768  * gdk_pango_layout_get_clip_region:
769  * @layout: a #PangoLayout 
770  * @x_origin: X pixel where you intend to draw the layout with this clip
771  * @y_origin: Y pixel where you intend to draw the layout with this clip
772  * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
773  * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
774  * 
775  * Obtains a clip region which contains the areas where the given ranges
776  * of text would be drawn. @x_origin and @y_origin are the same position
777  * you would pass to gdk_draw_layout_line(). @index_ranges should contain
778  * ranges of bytes in the layout's text.
779  * 
780  * Return value: a clip region containing the given ranges
781  **/
782 GdkRegion*
783 gdk_pango_layout_get_clip_region (PangoLayout *layout,
784                                   gint         x_origin,
785                                   gint         y_origin,
786                                   gint        *index_ranges,
787                                   gint         n_ranges)
788 {
789   PangoLayoutIter *iter;  
790   GdkRegion *clip_region;
791   
792   g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
793   g_return_val_if_fail (index_ranges != NULL, NULL);
794   
795   clip_region = gdk_region_new ();
796   
797   iter = pango_layout_get_iter (layout);
798   
799   do
800     {
801       PangoRectangle logical_rect;
802       PangoLayoutLine *line;
803       GdkRegion *line_region;
804       gint baseline;
805       
806       line = pango_layout_iter_get_line (iter);      
807
808       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
809       baseline = pango_layout_iter_get_baseline (iter);      
810
811       line_region = gdk_pango_layout_line_get_clip_region (line,
812                                                            x_origin + logical_rect.x / PANGO_SCALE,
813                                                            y_origin + baseline / PANGO_SCALE,
814                                                            index_ranges,
815                                                            n_ranges);
816
817       gdk_region_union (clip_region, line_region);
818       gdk_region_destroy (line_region);
819     }
820   while (pango_layout_iter_next_line (iter));
821
822   pango_layout_iter_free (iter);
823
824   return clip_region;
825 }