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