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