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