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