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