]> Pileus Git - ~andy/gtk/blob - gdk/gdkpango.c
Fix offset to center the underline in requested rectangle. (Ported from
[~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 <config.h>
21 #include <math.h>
22 #include <pango/pangocairo.h>
23 #include "gdkcairo.h"
24 #include "gdkcolor.h"
25 #include "gdkgc.h"
26 #include "gdkinternals.h"
27 #include "gdkpango.h"
28 #include "gdkrgb.h"
29 #include "gdkprivate.h"
30 #include "gdkscreen.h"
31 #include "gdkalias.h"
32
33 #include "gdkintl.h"
34
35 #define GDK_INFO_KEY "gdk-info"
36
37 /* We have various arrays indexed by render part; if PangoRenderPart
38  * is extended, we want to make sure not to overwrite the end of
39  * those arrays.
40  */
41 #define MAX_RENDER_PART  PANGO_RENDER_PART_STRIKETHROUGH
42
43 struct _GdkPangoRendererPrivate
44 {
45   GdkScreen *screen;
46
47   /* GdkPangoRenderer specific state */
48   PangoColor override_color[MAX_RENDER_PART + 1];
49   gboolean override_color_set[MAX_RENDER_PART + 1];
50   
51   GdkBitmap *stipple[MAX_RENDER_PART + 1];
52   gboolean embossed;
53
54   cairo_t *cr;
55   PangoRenderPart last_part;
56
57   /* Current target */
58   GdkDrawable *drawable;
59   GdkGC *base_gc;
60
61   gboolean gc_changed;
62 };
63
64 static PangoAttrType gdk_pango_attr_stipple_type;
65 static PangoAttrType gdk_pango_attr_embossed_type;
66
67 enum {
68   PROP_0,
69   PROP_SCREEN
70 };
71
72 G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
73
74 static void
75 gdk_pango_renderer_finalize (GObject *object)
76 {
77   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
78   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
79   int i;
80
81   if (priv->base_gc)
82     g_object_unref (priv->base_gc);
83   if (priv->drawable)
84     g_object_unref (priv->drawable);
85
86   for (i = 0; i <= MAX_RENDER_PART; i++)
87     if (priv->stipple[i])
88       g_object_unref (priv->stipple[i]);
89
90   G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
91 }
92
93 static GObject*
94 gdk_pango_renderer_constructor (GType                  type,
95                                 guint                  n_construct_properties,
96                                 GObjectConstructParam *construct_params)
97 {
98   GObject *object;
99   GdkPangoRenderer *gdk_renderer;
100
101   object = (* G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor) (type,
102                                                                               n_construct_properties,
103                                                                               construct_params);
104
105   gdk_renderer = GDK_PANGO_RENDERER (object);
106   
107   if (!gdk_renderer->priv->screen)
108     {
109       g_warning ("Screen must be specified at construct time for GdkPangoRenderer");
110       gdk_renderer->priv->screen = gdk_screen_get_default ();
111     }
112
113   return object;
114 }
115
116 /* Adjusts matrix and color for the renderer to draw the secondary
117  * "shadow" copy for embossed text */
118 static void
119 emboss_context (cairo_t *cr)
120 {
121   cairo_matrix_t tmp_matrix;
122
123   /* The gymnastics here to adjust the matrix are because we want
124    * to offset by +1,+1 in device-space, not in user-space,
125    * so we can't just draw the layout at x + 1, y + 1
126    */
127   cairo_get_matrix (cr, &tmp_matrix);
128   tmp_matrix.x0 += 1.0;
129   tmp_matrix.y0 += 1.0;
130   cairo_set_matrix (cr, &tmp_matrix);
131
132   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
133 }
134
135 static inline gboolean
136 color_equal (PangoColor *c1, PangoColor *c2)
137 {
138   if (!c1 && !c2)
139     return TRUE;
140
141   if (c1 && c2 &&
142       c1->red == c2->red &&
143       c1->green == c2->green &&
144       c1->blue == c2->blue)
145     return TRUE;
146
147   return FALSE;
148 }
149
150 static cairo_t *
151 get_cairo_context (GdkPangoRenderer *gdk_renderer,
152                    PangoRenderPart   part)
153 {
154   PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
155   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
156
157   if (!priv->cr)
158     {
159       const PangoMatrix *matrix;
160       
161       priv->cr = gdk_cairo_create (priv->drawable);
162
163       matrix = pango_renderer_get_matrix (renderer);
164       if (matrix)
165         {
166           cairo_matrix_t cairo_matrix;
167           
168           cairo_matrix_init (&cairo_matrix,
169                              matrix->xx, matrix->yx,
170                              matrix->xy, matrix->yy,
171                              matrix->x0, matrix->y0);
172           cairo_set_matrix (priv->cr, &cairo_matrix);
173         }
174     }
175
176   if (part != priv->last_part)
177     {
178       PangoColor *pango_color;
179       GdkColor *color;
180       GdkColor tmp_color;
181       gboolean changed;
182
183       pango_color = pango_renderer_get_color (renderer, part);
184       
185       if (priv->last_part != -1)
186         changed = priv->gc_changed ||
187           priv->stipple[priv->last_part] != priv->stipple[part] ||
188           !color_equal (pango_color,
189                         pango_renderer_get_color (renderer, priv->last_part));
190       else
191         changed = TRUE;
192       
193       if (changed)
194         {
195           if (pango_color)
196             {
197               tmp_color.red = pango_color->red;
198               tmp_color.green = pango_color->green;
199               tmp_color.blue = pango_color->blue;
200               
201               color = &tmp_color;
202             }
203           else
204             color = NULL;
205
206           _gdk_gc_update_context (priv->base_gc,
207                                   priv->cr,
208                                   color,
209                                   priv->stipple[part],
210                                   priv->gc_changed);
211         }
212
213       priv->last_part = part;
214       priv->gc_changed = FALSE;
215     }
216
217   return priv->cr;
218 }
219
220 static void
221 gdk_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
222                                 PangoFont        *font,
223                                 PangoGlyphString *glyphs,
224                                 int               x,
225                                 int               y)
226 {
227   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
228   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
229   cairo_t *cr;
230
231   cr = get_cairo_context (gdk_renderer, 
232                           PANGO_RENDER_PART_FOREGROUND);
233
234   if (priv->embossed)
235     {
236       cairo_save (cr);
237       emboss_context (cr);
238       cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
239       pango_cairo_show_glyph_string (cr, font, glyphs);
240       cairo_restore (cr);
241     }
242   
243   cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
244   pango_cairo_show_glyph_string (cr, font, glyphs);
245 }
246
247 /* Draws an error underline that looks like one of:
248  *              H       E                H
249  *     /\      /\      /\        /\      /\               -
250  *   A/  \    /  \    /  \     A/  \    /  \              |
251  *    \   \  /    \  /   /D     \   \  /    \             |
252  *     \   \/  C   \/   /        \   \/   C  \            | height = HEIGHT_SQUARES * square
253  *      \      /\  F   /          \  F   /\   \           | 
254  *       \    /  \    /            \    /  \   \G         |
255  *        \  /    \  /              \  /    \  /          |
256  *         \/      \/                \/      \/           -
257  *         B                         B       
258  *    |----|
259  *   unit_width = (HEIGHT_SQUARES - 1) * square
260  *
261  * The x, y, width, height passed in give the desired bounding box;
262  * x/width are adjusted to make the underline a integer number of units
263  * wide.
264  */
265 #define HEIGHT_SQUARES 2.5
266
267 /* Cut-and-pasted between here and pango/pango/pangocairo-render.c */
268 static void
269 draw_error_underline (cairo_t *cr,
270                       double  x,
271                       double  y,
272                       double  width,
273                       double  height)
274 {
275   double square = height / HEIGHT_SQUARES;
276   double unit_width = (HEIGHT_SQUARES - 1) * square;
277   int width_units = (width + unit_width / 2) / unit_width;
278   double y_top, y_bottom;
279   int i;
280
281   x += (width - width_units * unit_width) / 2;
282   width = width_units * unit_width;
283
284   y_top = y;
285   y_bottom = y + height;
286   
287   /* Bottom of squiggle */
288   cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
289   for (i = 0; i < width_units; i += 2)
290     {
291       double x_middle = x + (i + 1) * unit_width;
292       double x_right = x + (i + 2) * unit_width;
293     
294       cairo_line_to (cr, x_middle, y_bottom); /* B */
295       
296       if (i + 1 == width_units)
297         /* Nothing */;
298       else if (i + 2 == width_units)
299         cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
300       else
301         cairo_line_to (cr, x_right, y_top + square); /* C */
302     }
303   
304   /* Top of squiggle */
305   for (i -= 2; i >= 0; i -= 2)
306     {
307       double x_left = x + i * unit_width;
308       double x_middle = x + (i + 1) * unit_width;
309       double x_right = x + (i + 2) * unit_width;
310       
311       if (i + 1 == width_units)
312         cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
313       else {
314         if (i + 2 == width_units)
315           cairo_line_to (cr, x_right, y_top); /* E */
316         cairo_line_to (cr, x_middle, y_bottom - square); /* F */
317       }
318       
319       cairo_line_to (cr, x_left, y_top);   /* H */
320     }
321
322   cairo_close_path (cr);
323   cairo_fill (cr);
324 }
325
326 static void
327 gdk_pango_renderer_draw_rectangle (PangoRenderer    *renderer,
328                                    PangoRenderPart   part,
329                                    int               x,
330                                    int               y,
331                                    int               width,
332                                    int               height)
333 {
334   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
335   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
336   cairo_t *cr;
337   
338   cr = get_cairo_context (gdk_renderer, part);
339
340   if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
341     {
342       cairo_save (cr);
343       emboss_context (cr);
344       cairo_rectangle (cr,
345                        (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
346                        (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
347
348       cairo_fill (cr);
349       cairo_restore (cr);
350     }
351
352   cairo_rectangle (cr,
353                    (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
354                    (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
355   cairo_fill (cr);
356 }
357
358 static void
359 gdk_pango_renderer_draw_error_underline (PangoRenderer    *renderer,
360                                          int               x,
361                                          int               y,
362                                          int               width,
363                                          int               height)
364 {
365   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
366   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
367   cairo_t *cr;
368   
369   cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
370   
371   if (priv->embossed)
372     {
373       cairo_save (cr);
374       emboss_context (cr);
375       draw_error_underline (cr,
376                             (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
377                             (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
378       cairo_restore (cr);
379     }
380
381   draw_error_underline (cr,
382                         (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
383                         (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
384 }
385
386 static void
387 gdk_pango_renderer_part_changed (PangoRenderer   *renderer,
388                                  PangoRenderPart  part)
389 {
390   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
391
392   if (gdk_renderer->priv->last_part == part)
393     gdk_renderer->priv->last_part = (PangoRenderPart)-1;
394 }
395
396 static void
397 gdk_pango_renderer_begin (PangoRenderer *renderer)
398 {
399   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
400   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
401   
402   if (!priv->drawable || !priv->base_gc)
403     {
404       g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
405                  "must be used to set the target drawable and GC before using the renderer\n");
406     }
407 }
408
409 static void
410 gdk_pango_renderer_end (PangoRenderer *renderer)
411 {
412   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
413   GdkPangoRendererPrivate *priv = gdk_renderer->priv;
414
415   if (priv->cr)
416     {
417       cairo_destroy (priv->cr);
418       priv->cr = NULL;
419     }
420   priv->last_part = (PangoRenderPart)-1;
421 }
422
423 static void
424 gdk_pango_renderer_prepare_run (PangoRenderer  *renderer,
425                                 PangoLayoutRun *run)
426 {
427   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
428   gboolean embossed = FALSE;
429   GdkBitmap *stipple = NULL;
430   GSList *l;
431   int i;
432   
433   embossed = FALSE;
434   stipple = NULL;
435   
436   for (l = run->item->analysis.extra_attrs; l; l = l->next)
437     {
438       PangoAttribute *attr = l->data;
439
440       /* stipple_type and embossed_type aren't necessarily
441        * initialized, but they are 0, which is an
442        * invalid type so won't occur. 
443        */
444       if (attr->klass->type == gdk_pango_attr_stipple_type)
445         {
446           stipple = ((GdkPangoAttrStipple*)attr)->stipple;
447         }
448       else if (attr->klass->type == gdk_pango_attr_embossed_type)
449         {
450           embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
451         }
452     }
453
454   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
455   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple);
456   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple);
457   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple);
458
459   if (embossed != gdk_renderer->priv->embossed)
460     {
461       gdk_renderer->priv->embossed = embossed;
462       pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
463     }
464
465   PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
466
467   for (i = 0; i <= MAX_RENDER_PART; i++)
468     {
469       if (gdk_renderer->priv->override_color_set[i])
470         pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]);
471     }
472 }
473
474 static void
475 gdk_pango_renderer_set_property (GObject         *object,
476                                  guint            prop_id,
477                                  const GValue    *value,
478                                  GParamSpec      *pspec)
479 {
480   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
481
482   switch (prop_id)
483     {
484     case PROP_SCREEN:
485       gdk_renderer->priv->screen = g_value_get_object (value);
486       break;
487     default:
488       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
489       break;
490     }
491 }
492
493 static void
494 gdk_pango_renderer_get_property (GObject    *object,
495                                  guint       prop_id,
496                                  GValue     *value,
497                                  GParamSpec *pspec)
498 {
499   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
500
501   switch (prop_id)
502     {
503     case PROP_SCREEN:
504       g_value_set_object (value, gdk_renderer->priv->screen);
505       break;
506     default:
507       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
508       break;
509     }
510 }
511
512 static void
513 gdk_pango_renderer_init (GdkPangoRenderer *renderer)
514 {
515   renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
516                                                 GDK_TYPE_PANGO_RENDERER,
517                                                 GdkPangoRendererPrivate);
518
519   renderer->priv->last_part = (PangoRenderPart)-1;
520   renderer->priv->gc_changed = TRUE;
521 }
522
523 static void
524 gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
525 {
526   GObjectClass *object_class = G_OBJECT_CLASS (klass);
527   
528   PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
529   
530   renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
531   renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
532   renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
533   renderer_class->part_changed = gdk_pango_renderer_part_changed;
534   renderer_class->begin = gdk_pango_renderer_begin;
535   renderer_class->end = gdk_pango_renderer_end;
536   renderer_class->prepare_run = gdk_pango_renderer_prepare_run;
537
538   object_class->finalize = gdk_pango_renderer_finalize;
539   object_class->constructor = gdk_pango_renderer_constructor;
540   object_class->set_property = gdk_pango_renderer_set_property;
541   object_class->get_property = gdk_pango_renderer_get_property;
542   
543   g_object_class_install_property (object_class,
544                                    PROP_SCREEN,
545                                    g_param_spec_object ("screen",
546                                                         P_("Screen"),
547                                                         P_("the GdkScreen for the renderer"),
548                                                         GDK_TYPE_SCREEN,
549                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
550                                                         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | 
551                                                         G_PARAM_STATIC_BLURB));
552
553   g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));  
554 }
555
556 /**
557  * gdk_pango_renderer_new:
558  * @screen: a #GdkScreen
559  * 
560  * Creates a new #PangoRenderer for @screen. Normally you can use the
561  * results of gdk_pango_renderer_get_default() rather than creating a new
562  * renderer.
563  * 
564  * Return value: a newly created #PangoRenderer. Free with g_object_unref().
565  *
566  * Since: 2.6
567  **/
568 PangoRenderer *
569 gdk_pango_renderer_new (GdkScreen *screen)
570 {
571   g_return_val_if_fail (screen != NULL, NULL);
572   
573   return g_object_new (GDK_TYPE_PANGO_RENDERER,
574                        "screen", screen,
575                        NULL);
576 }
577
578 static void
579 on_renderer_display_closed (GdkDisplay       *display,
580                             gboolean          is_error,
581                             GdkPangoRenderer *renderer)
582 {
583   g_signal_handlers_disconnect_by_func (display,
584                                         on_renderer_display_closed,
585                                         renderer);
586   g_object_set_data (G_OBJECT (renderer->priv->screen),
587                      g_intern_static_string ("gdk-pango-renderer"), NULL);
588 }
589
590 /**
591  * gdk_pango_renderer_get_default:
592  * @screen: a #GdkScreen
593  * 
594  * Gets the default #PangoRenderer for a screen. This default renderer
595  * is shared by all users of the display, so properties such as the color
596  * or transformation matrix set for the renderer may be overwritten
597  * by functions such as gdk_draw_layout().
598  *
599  * Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
600  * and gdk_pango_renderer_set_gc() to set the drawable and graphics context
601  * to use for drawing.
602  * 
603  * Return value: the default #PangoRenderer for @screen. The
604  *  renderer is owned by GTK+ and will be kept around until the
605  *  screen is closed.
606  *
607  * Since: 2.6
608  **/
609 PangoRenderer *
610 gdk_pango_renderer_get_default (GdkScreen *screen)
611 {
612   PangoRenderer *renderer;
613
614   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
615   
616   renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer");
617   if (!renderer)
618     {
619       renderer = gdk_pango_renderer_new (screen);
620       g_object_set_data_full (G_OBJECT (screen), 
621                               g_intern_static_string ("gdk-pango-renderer"), renderer,
622                               (GDestroyNotify)g_object_unref);
623
624       g_signal_connect (gdk_screen_get_display (screen), "closed",
625                         G_CALLBACK (on_renderer_display_closed), renderer);
626     }
627
628   return renderer;
629 }
630
631 /**
632  * gdk_pango_renderer_set_drawable:
633  * @gdk_renderer: a #GdkPangoRenderer
634  * @drawable: the new target drawable, or %NULL
635  * 
636  * Sets the drawable the renderer draws to.
637  *
638  * Since: 2.6
639  **/
640 void
641 gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
642                                  GdkDrawable      *drawable)
643 {
644   GdkPangoRendererPrivate *priv;
645   
646   g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
647   g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
648
649   priv = gdk_renderer->priv;
650   
651   if (priv->drawable != drawable)
652     {
653       if (priv->drawable)
654         g_object_unref (priv->drawable);
655       priv->drawable = drawable;
656       if (priv->drawable)
657         g_object_ref (priv->drawable);
658     }
659 }
660
661 /**
662  * gdk_pango_renderer_set_gc:
663  * @gdk_renderer: a #GdkPangoRenderer
664  * @gc: the new GC to use for drawing, or %NULL
665  * 
666  * Sets the GC the renderer draws with. Note that the GC must not be
667  * modified until it is unset by calling the function again with
668  * %NULL for the @gc parameter, since GDK may make internal copies
669  * of the GC which won't be updated to follow changes to the
670  * original GC.
671  *
672  * Since: 2.6
673  **/
674 void
675 gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
676                            GdkGC            *gc)
677 {
678   GdkPangoRendererPrivate *priv;
679   
680   g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
681   g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
682
683   priv = gdk_renderer->priv;
684   
685   if (priv->base_gc != gc)
686     {
687       if (priv->base_gc)
688         g_object_unref (priv->base_gc);
689       priv->base_gc = gc;
690       if (priv->base_gc)
691         g_object_ref (priv->base_gc);
692
693       priv->gc_changed = TRUE;
694     }
695 }
696
697
698 /**
699  * gdk_pango_renderer_set_stipple:
700  * @gdk_renderer: a #GdkPangoRenderer
701  * @part: the part to render with the stipple
702  * @stipple: the new stipple value.
703  * 
704  * Sets the stipple for one render part (foreground, background, underline,
705  * etc.) Note that this is overwritten when iterating through the individual
706  * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus
707  * only useful when you call low level functions like pango_renderer_draw_glyphs()
708  * directly, or in the 'prepare_run' virtual function of a subclass of
709  * #GdkPangoRenderer.
710  *
711  * Since: 2.6
712  **/
713 void
714 gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer,
715                                 PangoRenderPart   part,
716                                 GdkBitmap        *stipple)
717 {
718   g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
719
720   if (part > MAX_RENDER_PART)   /* Silently ignore unknown parts */
721     return;
722
723   if (stipple != gdk_renderer->priv->stipple[part])
724     {
725       if (gdk_renderer->priv->stipple[part])
726         g_object_unref (gdk_renderer->priv->stipple[part]);
727
728       gdk_renderer->priv->stipple[part] = stipple;
729       
730       if (gdk_renderer->priv->stipple[part])
731         g_object_ref (gdk_renderer->priv->stipple[part]);
732
733       pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
734     }
735 }
736
737 /**
738  * gdk_pango_renderer_set_override_color:
739  * @gdk_renderer: a #GdkPangoRenderer
740  * @part: the part to render to set the color of
741  * @color: the color to use, or %NULL to unset a previously
742  *         set override color.
743  * 
744  * Sets the color for a particular render part (foreground,
745  * background, underline, etc.), overriding any attributes on the layouts
746  * renderered with this renderer.
747  * 
748  * Since: 2.6
749  **/
750 void
751 gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
752                                        PangoRenderPart   part,
753                                        const GdkColor   *color)
754 {
755   GdkPangoRendererPrivate *priv;
756   
757   g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
758
759   priv = gdk_renderer->priv;
760   
761   if (part > MAX_RENDER_PART)   /* Silently ignore unknown parts */
762     return;
763
764   if (color)
765     {
766       priv->override_color[part].red = color->red;
767       priv->override_color[part].green = color->green;
768       priv->override_color[part].blue = color->blue;
769       priv->override_color_set[part] = TRUE;
770     }
771   else
772     priv->override_color_set[part] = FALSE;
773 }
774
775 /**
776  * gdk_pango_context_set_colormap:
777  * @context: a #PangoContext
778  * @colormap: a #GdkColormap
779  *
780  * This function used to set the colormap to be used for drawing with
781  * @context. The colormap is now always derived from the graphics
782  * context used for drawing, so calling this function is no longer
783  * necessary.
784  **/
785 void
786 gdk_pango_context_set_colormap (PangoContext *context,
787                                 GdkColormap  *colormap)
788 {
789   g_return_if_fail (PANGO_IS_CONTEXT (context));
790   g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
791 }
792
793 /* Gets a renderer to draw with, setting the properties of the
794  * renderer and activating it. Note that since we activate the
795  * renderer here, the implicit setting of the matrix that
796  * pango_renderer_draw_layout_[line] normally do when they
797  * activate the renderer is suppressed. */
798 static PangoRenderer *
799 get_renderer (GdkDrawable     *drawable,
800               GdkGC           *gc,
801               const GdkColor  *foreground,
802               const GdkColor  *background)
803 {
804   GdkScreen *screen = gdk_drawable_get_screen (drawable);
805   PangoRenderer *renderer = gdk_pango_renderer_get_default (screen);
806   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
807
808   gdk_pango_renderer_set_drawable (gdk_renderer, drawable);
809   gdk_pango_renderer_set_gc (gdk_renderer, gc);  
810
811   gdk_pango_renderer_set_override_color (gdk_renderer,
812                                          PANGO_RENDER_PART_FOREGROUND,
813                                          foreground);
814   gdk_pango_renderer_set_override_color (gdk_renderer,
815                                          PANGO_RENDER_PART_UNDERLINE,
816                                          foreground);
817   gdk_pango_renderer_set_override_color (gdk_renderer,
818                                          PANGO_RENDER_PART_STRIKETHROUGH,
819                                          foreground);
820
821   gdk_pango_renderer_set_override_color (gdk_renderer,
822                                          PANGO_RENDER_PART_BACKGROUND,
823                                          background);
824
825   pango_renderer_activate (renderer);
826
827   return renderer;
828 }
829
830 /* Cleans up the renderer obtained with get_renderer() */
831 static void
832 release_renderer (PangoRenderer *renderer)
833 {
834   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
835   
836   pango_renderer_deactivate (renderer);
837   
838   gdk_pango_renderer_set_override_color (gdk_renderer,
839                                          PANGO_RENDER_PART_FOREGROUND,
840                                          NULL);
841   gdk_pango_renderer_set_override_color (gdk_renderer,
842                                          PANGO_RENDER_PART_UNDERLINE,
843                                          NULL);
844   gdk_pango_renderer_set_override_color (gdk_renderer,
845                                          PANGO_RENDER_PART_STRIKETHROUGH,
846                                          NULL);
847   gdk_pango_renderer_set_override_color (gdk_renderer,
848                                          PANGO_RENDER_PART_BACKGROUND,
849                                          NULL);
850   
851   gdk_pango_renderer_set_drawable (gdk_renderer, NULL);
852   gdk_pango_renderer_set_gc (gdk_renderer, NULL);
853 }
854
855 /**
856  * gdk_draw_layout_line_with_colors:
857  * @drawable:  the drawable on which to draw the line
858  * @gc:        base graphics to use
859  * @x:         the x position of start of string (in pixels)
860  * @y:         the y position of baseline (in pixels)
861  * @line:      a #PangoLayoutLine
862  * @foreground: foreground override color, or %NULL for none
863  * @background: background override color, or %NULL for none
864  *
865  * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
866  * layout's normal colors with @foreground and/or @background.
867  * @foreground and @background need not be allocated.
868  *
869  * If the layout's #PangoContext has a transformation matrix set, then
870  * @x and @y specify the position of the left edge of the baseline
871  * (left is in before-tranform user coordinates) in after-transform
872  * device coordinates.
873  */
874 void 
875 gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
876                                   GdkGC            *gc,
877                                   gint              x, 
878                                   gint              y,
879                                   PangoLayoutLine  *line,
880                                   const GdkColor   *foreground,
881                                   const GdkColor   *background)
882 {
883   PangoRenderer *renderer;
884   const PangoMatrix *matrix;
885   
886   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
887   g_return_if_fail (GDK_IS_GC (gc));
888   g_return_if_fail (line != NULL);
889
890   renderer = get_renderer (drawable, gc, foreground, background);
891
892   /* When we have a matrix, we do positioning by adjusting the matrix, and
893    * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
894    * a matrix when the caller didn't provide one, however, since that adds
895    * lots of floating point arithmetic for each glyph.
896    */
897   matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
898   if (matrix)
899     {
900       PangoMatrix tmp_matrix;
901       
902       tmp_matrix = *matrix;
903       tmp_matrix.x0 = x;
904       tmp_matrix.y0 = y;
905       pango_renderer_set_matrix (renderer, &tmp_matrix);
906
907       x = 0;
908       y = 0;
909     }
910   else
911     pango_renderer_set_matrix (renderer, NULL);
912
913   pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
914
915   release_renderer (renderer);
916 }
917
918 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
919  * between here and gtklabel.c */
920 static void
921 get_rotated_layout_bounds (PangoLayout  *layout,
922                            GdkRectangle *rect)
923 {
924   PangoContext *context = pango_layout_get_context (layout);
925   const PangoMatrix *matrix = pango_context_get_matrix (context);
926   gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
927   PangoRectangle logical_rect;
928   gint i, j;
929
930   pango_layout_get_extents (layout, NULL, &logical_rect);
931   
932   for (i = 0; i < 2; i++)
933     {
934       gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
935       for (j = 0; j < 2; j++)
936         {
937           gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
938           
939           gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
940           gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
941           
942           if (i == 0 && j == 0)
943             {
944               x_min = x_max = xt;
945               y_min = y_max = yt;
946             }
947           else
948             {
949               if (xt < x_min)
950                 x_min = xt;
951               if (yt < y_min)
952                 y_min = yt;
953               if (xt > x_max)
954                 x_max = xt;
955               if (yt > y_max)
956                 y_max = yt;
957             }
958         }
959     }
960   
961   rect->x = floor (x_min);
962   rect->width = ceil (x_max) - rect->x;
963   rect->y = floor (y_min);
964   rect->height = floor (y_max) - rect->y;
965 }
966
967 /**
968  * gdk_draw_layout_with_colors:
969  * @drawable:  the drawable on which to draw string
970  * @gc:        base graphics context to use
971  * @x:         the X position of the left of the layout (in pixels)
972  * @y:         the Y position of the top of the layout (in pixels)
973  * @layout:    a #PangoLayout
974  * @foreground: foreground override color, or %NULL for none
975  * @background: background override color, or %NULL for none
976  *
977  * Render a #PangoLayout onto a #GdkDrawable, overriding the
978  * layout's normal colors with @foreground and/or @background.
979  * @foreground and @background need not be allocated.
980  *
981  * If the layout's #PangoContext has a transformation matrix set, then
982  * @x and @y specify the position of the top left corner of the
983  * bounding box (in device space) of the transformed layout.
984  *
985  * If you're using GTK+, the ususal way to obtain a #PangoLayout
986  * is gtk_widget_create_pango_layout().
987  */
988 void 
989 gdk_draw_layout_with_colors (GdkDrawable     *drawable,
990                              GdkGC           *gc,
991                              int              x, 
992                              int              y,
993                              PangoLayout     *layout,
994                              const GdkColor  *foreground,
995                              const GdkColor  *background)
996 {
997   PangoRenderer *renderer;
998   const PangoMatrix *matrix;
999   
1000   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1001   g_return_if_fail (GDK_IS_GC (gc));
1002   g_return_if_fail (PANGO_IS_LAYOUT (layout));
1003
1004   renderer = get_renderer (drawable, gc, foreground, background);
1005
1006   /* When we have a matrix, we do positioning by adjusting the matrix, and
1007    * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
1008    * a matrix when the caller didn't provide one, however, since that adds
1009    * lots of floating point arithmetic for each glyph.
1010    */
1011   matrix = pango_context_get_matrix (pango_layout_get_context (layout));
1012   if (matrix)
1013     {
1014       PangoMatrix tmp_matrix;
1015       GdkRectangle rect;
1016
1017       get_rotated_layout_bounds (layout, &rect);
1018       
1019       tmp_matrix = *matrix;
1020       tmp_matrix.x0 += x - rect.x;
1021       tmp_matrix.y0 += y - rect.y;
1022       pango_renderer_set_matrix (renderer, &tmp_matrix);
1023       
1024       x = 0;
1025       y = 0;
1026     }
1027   else
1028     pango_renderer_set_matrix (renderer, NULL);
1029
1030   pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
1031   
1032   release_renderer (renderer);
1033 }
1034
1035 /**
1036  * gdk_draw_layout_line:
1037  * @drawable:  the drawable on which to draw the line
1038  * @gc:        base graphics to use
1039  * @x:         the x position of start of string (in pixels)
1040  * @y:         the y position of baseline (in pixels)
1041  * @line:      a #PangoLayoutLine
1042  *
1043  * Render a #PangoLayoutLine onto an GDK drawable
1044  *
1045  * If the layout's #PangoContext has a transformation matrix set, then
1046  * @x and @y specify the position of the left edge of the baseline
1047  * (left is in before-tranform user coordinates) in after-transform
1048  * device coordinates.
1049  */
1050 void 
1051 gdk_draw_layout_line (GdkDrawable      *drawable,
1052                       GdkGC            *gc,
1053                       gint              x, 
1054                       gint              y,
1055                       PangoLayoutLine  *line)
1056 {
1057   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1058   g_return_if_fail (GDK_IS_GC (gc));
1059   g_return_if_fail (line != NULL);
1060   
1061   gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
1062 }
1063
1064 /**
1065  * gdk_draw_layout:
1066  * @drawable:  the drawable on which to draw string
1067  * @gc:        base graphics context to use
1068  * @x:         the X position of the left of the layout (in pixels)
1069  * @y:         the Y position of the top of the layout (in pixels)
1070  * @layout:    a #PangoLayout
1071  *
1072  * Render a #PangoLayout onto a GDK drawable
1073  *
1074  * If the layout's #PangoContext has a transformation matrix set, then
1075  * @x and @y specify the position of the top left corner of the
1076  * bounding box (in device space) of the transformed layout.
1077  *
1078  * If you're using GTK+, the usual way to obtain a #PangoLayout
1079  * is gtk_widget_create_pango_layout().
1080  */
1081 void 
1082 gdk_draw_layout (GdkDrawable     *drawable,
1083                  GdkGC           *gc,
1084                  int              x, 
1085                  int              y,
1086                  PangoLayout     *layout)
1087 {
1088   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1089   g_return_if_fail (GDK_IS_GC (gc));
1090   g_return_if_fail (PANGO_IS_LAYOUT (layout));
1091
1092   gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
1093 }
1094
1095 static PangoAttribute *
1096 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
1097 {
1098   const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
1099
1100   return gdk_pango_attr_stipple_new (src->stipple);
1101 }
1102
1103 static void
1104 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
1105 {
1106   GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
1107
1108   if (st->stipple)
1109     g_object_unref (st->stipple);
1110   
1111   g_free (attr);
1112 }
1113
1114 static gboolean
1115 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
1116                                     const PangoAttribute *attr2)
1117 {
1118   const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
1119   const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
1120
1121   return a->stipple == b->stipple;
1122 }
1123
1124 /**
1125  * gdk_pango_attr_stipple_new:
1126  * @stipple: a bitmap to be set as stipple
1127  *
1128  * Creates a new attribute containing a stipple bitmap to be used when
1129  * rendering the text.
1130  *
1131  * Return value: new #PangoAttribute
1132  **/
1133
1134 PangoAttribute *
1135 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
1136 {
1137   GdkPangoAttrStipple *result;
1138   
1139   static PangoAttrClass klass = {
1140     0,
1141     gdk_pango_attr_stipple_copy,
1142     gdk_pango_attr_stipple_destroy,
1143     gdk_pango_attr_stipple_compare
1144   };
1145
1146   if (!klass.type)
1147     klass.type = gdk_pango_attr_stipple_type =
1148       pango_attr_type_register ("GdkPangoAttrStipple");
1149
1150   result = g_new (GdkPangoAttrStipple, 1);
1151   result->attr.klass = &klass;
1152
1153   if (stipple)
1154     g_object_ref (stipple);
1155   
1156   result->stipple = stipple;
1157
1158   return (PangoAttribute *)result;
1159 }
1160
1161 static PangoAttribute *
1162 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
1163 {
1164   const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
1165
1166   return gdk_pango_attr_embossed_new (e->embossed);
1167 }
1168
1169 static void
1170 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
1171 {
1172   g_free (attr);
1173 }
1174
1175 static gboolean
1176 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
1177                                  const PangoAttribute *attr2)
1178 {
1179   const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
1180   const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
1181
1182   return e1->embossed == e2->embossed;
1183 }
1184
1185 /**
1186  * gdk_pango_attr_embossed_new:
1187  * @embossed: a bitmap to be set as embossed
1188  *
1189  * Creates a new attribute containing a embossed bitmap to be used when
1190  * rendering the text.
1191  *
1192  * Return value: new #PangoAttribute
1193  **/
1194
1195 PangoAttribute *
1196 gdk_pango_attr_embossed_new (gboolean embossed)
1197 {
1198   GdkPangoAttrEmbossed *result;
1199   
1200   static PangoAttrClass klass = {
1201     0,
1202     gdk_pango_attr_embossed_copy,
1203     gdk_pango_attr_embossed_destroy,
1204     gdk_pango_attr_embossed_compare
1205   };
1206
1207   if (!klass.type)
1208     klass.type = gdk_pango_attr_embossed_type =
1209       pango_attr_type_register ("GdkPangoAttrEmbossed");
1210
1211   result = g_new (GdkPangoAttrEmbossed, 1);
1212   result->attr.klass = &klass;
1213   result->embossed = embossed;
1214   
1215   return (PangoAttribute *)result;
1216 }
1217
1218 /* Get a clip region to draw only part of a layout. index_ranges
1219  * contains alternating range starts/stops. The region is the
1220  * region which contains the given ranges, i.e. if you draw with the
1221  * region as clip, only the given ranges are drawn.
1222  */
1223
1224 /**
1225  * gdk_pango_layout_line_get_clip_region:
1226  * @line: a #PangoLayoutLine 
1227  * @x_origin: X pixel where you intend to draw the layout line with this clip
1228  * @y_origin: baseline pixel where you intend to draw the layout line with this clip
1229  * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1230  * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1231  * 
1232  * Obtains a clip region which contains the areas where the given
1233  * ranges of text would be drawn. @x_origin and @y_origin are the same
1234  * position you would pass to gdk_draw_layout_line(). @index_ranges
1235  * should contain ranges of bytes in the layout's text. The clip
1236  * region will include space to the left or right of the line (to the
1237  * layout bounding box) if you have indexes above or below the indexes
1238  * contained inside the line. This is to draw the selection all the way
1239  * to the side of the layout. However, the clip region is in line coordinates,
1240  * not layout coordinates.
1241  * 
1242  * Return value: a clip region containing the given ranges
1243  **/
1244 GdkRegion*
1245 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
1246                                        gint             x_origin,
1247                                        gint             y_origin,
1248                                        gint            *index_ranges,
1249                                        gint             n_ranges)
1250 {
1251   GdkRegion *clip_region;
1252   gint i;
1253   PangoRectangle logical_rect;
1254   PangoLayoutIter *iter;
1255   gint baseline;
1256   
1257   g_return_val_if_fail (line != NULL, NULL);
1258   g_return_val_if_fail (index_ranges != NULL, NULL);
1259   
1260   clip_region = gdk_region_new ();
1261
1262   iter = pango_layout_get_iter (line->layout);
1263   while (pango_layout_iter_get_line (iter) != line)
1264     pango_layout_iter_next_line (iter);
1265   
1266   pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1267   baseline = pango_layout_iter_get_baseline (iter);
1268   
1269   pango_layout_iter_free (iter);
1270   
1271   i = 0;
1272   while (i < n_ranges)
1273     {  
1274       gint *pixel_ranges = NULL;
1275       gint n_pixel_ranges = 0;
1276       gint j;
1277
1278       /* Note that get_x_ranges returns layout coordinates
1279        */
1280       if (index_ranges[i*2+1] >= line->start_index &&
1281           index_ranges[i*2] < line->start_index + line->length)
1282         pango_layout_line_get_x_ranges (line,
1283                                         index_ranges[i*2],
1284                                         index_ranges[i*2+1],
1285                                         &pixel_ranges, &n_pixel_ranges);
1286   
1287       for (j = 0; j < n_pixel_ranges; j++)
1288         {
1289           GdkRectangle rect;
1290           
1291           rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
1292           rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
1293           rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
1294           rect.height = logical_rect.height / PANGO_SCALE;
1295           
1296           gdk_region_union_with_rect (clip_region, &rect);
1297         }
1298
1299       g_free (pixel_ranges);
1300       ++i;
1301     }
1302
1303   return clip_region;
1304 }
1305
1306 /**
1307  * gdk_pango_layout_get_clip_region:
1308  * @layout: a #PangoLayout 
1309  * @x_origin: X pixel where you intend to draw the layout with this clip
1310  * @y_origin: Y pixel where you intend to draw the layout with this clip
1311  * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1312  * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1313  * 
1314  * Obtains a clip region which contains the areas where the given ranges
1315  * of text would be drawn. @x_origin and @y_origin are the same position
1316  * you would pass to gdk_draw_layout_line(). @index_ranges should contain
1317  * ranges of bytes in the layout's text.
1318  * 
1319  * Return value: a clip region containing the given ranges
1320  **/
1321 GdkRegion*
1322 gdk_pango_layout_get_clip_region (PangoLayout *layout,
1323                                   gint         x_origin,
1324                                   gint         y_origin,
1325                                   gint        *index_ranges,
1326                                   gint         n_ranges)
1327 {
1328   PangoLayoutIter *iter;  
1329   GdkRegion *clip_region;
1330   
1331   g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
1332   g_return_val_if_fail (index_ranges != NULL, NULL);
1333   
1334   clip_region = gdk_region_new ();
1335   
1336   iter = pango_layout_get_iter (layout);
1337   
1338   do
1339     {
1340       PangoRectangle logical_rect;
1341       PangoLayoutLine *line;
1342       GdkRegion *line_region;
1343       gint baseline;
1344       
1345       line = pango_layout_iter_get_line (iter);      
1346
1347       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1348       baseline = pango_layout_iter_get_baseline (iter);      
1349
1350       line_region = gdk_pango_layout_line_get_clip_region (line,
1351                                                            x_origin + logical_rect.x / PANGO_SCALE,
1352                                                            y_origin + baseline / PANGO_SCALE,
1353                                                            index_ranges,
1354                                                            n_ranges);
1355
1356       gdk_region_union (clip_region, line_region);
1357       gdk_region_destroy (line_region);
1358     }
1359   while (pango_layout_iter_next_line (iter));
1360
1361   pango_layout_iter_free (iter);
1362
1363   return clip_region;
1364 }
1365
1366 /**
1367  * gdk_pango_context_get:
1368  * 
1369  * Creates a #PangoContext for the default GDK screen.
1370  *
1371  * The context must be freed when you're finished with it.
1372  * 
1373  * When using GTK+, normally you should use gtk_widget_get_pango_context()
1374  * instead of this function, to get the appropriate context for
1375  * the widget you intend to render text onto.
1376  * 
1377  * The newly created context will have the default font options (see
1378  * #cairo_font_options_t) for the default screen; if these options
1379  * change it will not be updated. Using gtk_widget_get_pango_context()
1380  * is more convenient if you want to keep a context around and track
1381  * changes to the screen's font rendering settings.
1382  *
1383  * Return value: a new #PangoContext for the default display
1384  **/
1385 PangoContext *
1386 gdk_pango_context_get (void)
1387 {
1388   return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
1389 }
1390
1391 /**
1392  * gdk_pango_context_get_for_screen:
1393  * @screen: the #GdkScreen for which the context is to be created.
1394  * 
1395  * Creates a #PangoContext for @screen.
1396  *
1397  * The context must be freed when you're finished with it.
1398  * 
1399  * When using GTK+, normally you should use gtk_widget_get_pango_context()
1400  * instead of this function, to get the appropriate context for
1401  * the widget you intend to render text onto.
1402  * 
1403  * The newly created context will have the default font options
1404  * (see #cairo_font_options_t) for the screen; if these options
1405  * change it will not be updated. Using gtk_widget_get_pango_context()
1406  * is more convenient if you want to keep a context around and track
1407  * changes to the screen's font rendering settings.
1408  * 
1409  * Return value: a new #PangoContext for @screen
1410  *
1411  * Since: 2.2
1412  **/
1413 PangoContext *
1414 gdk_pango_context_get_for_screen (GdkScreen *screen)
1415 {
1416   PangoFontMap *fontmap;
1417   PangoContext *context;
1418   const cairo_font_options_t *options;
1419   double dpi;
1420   
1421   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1422
1423   fontmap = pango_cairo_font_map_get_default ();
1424   
1425   context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
1426
1427   options = gdk_screen_get_font_options (screen);
1428   pango_cairo_context_set_font_options (context, options);
1429
1430   dpi = gdk_screen_get_resolution (screen);
1431   pango_cairo_context_set_resolution (context, dpi);
1432
1433   return context;
1434 }
1435
1436 #define __GDK_PANGO_C__
1437 #include "gdkaliasdef.c"