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