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