]> Pileus Git - ~andy/gtk/blob - gdk/gdkpango.c
Remove all references to offscreen flag which was no longer used.
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 "gdkcolor.h"
21 #include "gdkgc.h"
22 #include "gdkpango.h"
23 #include "gdkprivate.h"
24
25 #define GDK_INFO_KEY "gdk-info"
26
27 typedef struct _GdkPangoContextInfo GdkPangoContextInfo;
28
29 struct _GdkPangoContextInfo
30 {
31   GdkColormap *colormap;
32 };
33
34 static void gdk_pango_get_item_properties (PangoItem      *item,
35                                            PangoUnderline *uline,
36                                            PangoAttrColor *fg_color,
37                                            gboolean       *fg_set,
38                                            PangoAttrColor *bg_color,
39                                            gboolean       *bg_set);
40
41 static void
42 gdk_pango_context_destroy (GdkPangoContextInfo *info)
43 {
44   gdk_colormap_unref (info->colormap);
45   g_free (info);
46 }
47
48 static GdkPangoContextInfo *
49 gdk_pango_context_get_info (PangoContext *context, gboolean create)
50 {
51   GdkPangoContextInfo *info = pango_context_get_data (context, GDK_INFO_KEY);
52   if (!info && create)
53     {
54       info = g_new (GdkPangoContextInfo, 1);
55       info->colormap = NULL;
56
57       pango_context_set_data (context, GDK_INFO_KEY,
58                               info, (GDestroyNotify)gdk_pango_context_destroy);
59     }
60
61   return info;
62 }
63
64 static GdkGC *
65 gdk_pango_get_gc (PangoContext   *context,
66                   PangoAttrColor *fg_color,
67                   GdkGC          *base_gc)
68 {
69   GdkPangoContextInfo *info;
70   GdkColormap *colormap;
71   GdkColor color;
72   
73   g_return_val_if_fail (context != NULL, NULL);
74
75   info = gdk_pango_context_get_info (context, FALSE);
76
77   if (info && info->colormap)
78     colormap = info->colormap;
79   else
80     colormap = gdk_colormap_get_system();
81
82   /* FIXME. FIXME. FIXME. Only works for true color */
83
84   color.red = fg_color->red;
85   color.green = fg_color->green;
86   color.blue = fg_color->blue;
87   
88   if (gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE))
89     {
90       GdkGC *result = gdk_gc_new (gdk_parent_root);
91       gdk_gc_copy (result, base_gc);
92       gdk_gc_set_foreground (result, &color);
93
94       return result;
95     }
96   else
97     return gdk_gc_ref (base_gc);
98 }
99
100 static void
101 gdk_pango_free_gc (PangoContext *context,
102                    GdkGC        *gc)
103 {
104   gdk_gc_unref (gc);
105 }
106
107 void
108 gdk_pango_context_set_colormap (PangoContext *context,
109                                 GdkColormap  *colormap)
110 {
111   GdkPangoContextInfo *info;
112   
113   g_return_if_fail (context != NULL);
114
115   info = gdk_pango_context_get_info (context, TRUE);
116   g_return_if_fail (info != NULL);
117   
118   if (info->colormap != colormap)
119     {
120       if (info->colormap)
121         gdk_colormap_unref (info->colormap);
122
123       info->colormap = colormap;
124       
125       if (info->colormap)
126         gdk_colormap_ref (info->colormap);
127     }
128 }
129
130
131 /**
132  * gdk_draw_layout_line:
133  * @drawable:  the drawable on which to draw the line
134  * @gc:        base graphics to use
135  * @x:         the x position of start of string (in pixels)
136  * @y:         the y position of baseline (in pixels)
137  * @line:      a #PangoLayoutLine
138  *
139  * Render a #PangoLayoutLine onto an GDK drawable
140  */
141 void 
142 gdk_draw_layout_line (GdkDrawable      *drawable,
143                       GdkGC            *gc,
144                       gint              x, 
145                       gint              y,
146                       PangoLayoutLine  *line)
147 {
148   GSList *tmp_list = line->runs;
149   PangoRectangle overall_rect;
150   PangoRectangle logical_rect;
151   PangoRectangle ink_rect;
152   PangoContext *context;
153   gint x_off = 0;
154
155   g_return_if_fail (drawable != NULL);
156   g_return_if_fail (gc != NULL);
157   g_return_if_fail (line != NULL);
158
159   if (GDK_DRAWABLE_DESTROYED (drawable))
160     return;
161
162   context = pango_layout_get_context (line->layout);
163   
164   pango_layout_line_get_extents (line,NULL, &overall_rect);
165   
166   while (tmp_list)
167     {
168       PangoUnderline uline = PANGO_UNDERLINE_NONE;
169       PangoLayoutRun *run = tmp_list->data;
170       PangoAttrColor fg_color, bg_color;
171       gboolean fg_set, bg_set;
172       GdkGC *fg_gc;
173       
174       tmp_list = tmp_list->next;
175
176       gdk_pango_get_item_properties (run->item, &uline, &fg_color, &fg_set, &bg_color, &bg_set);
177
178       if (fg_set)
179         fg_gc = gdk_pango_get_gc (context, &fg_color, gc);
180       else
181         fg_gc = gc;
182
183       if (uline == PANGO_UNDERLINE_NONE)
184         pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
185                                     NULL, &logical_rect);
186       else
187         pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
188                                     &ink_rect, &logical_rect);
189
190       if (bg_set)
191         {
192           GdkGC *bg_gc = gdk_pango_get_gc (context, &bg_color, gc);
193
194           gdk_draw_rectangle (drawable, bg_gc, TRUE,
195                               x + (x_off + logical_rect.x) / PANGO_SCALE,
196                               y + overall_rect.y / PANGO_SCALE,
197                               logical_rect.width / PANGO_SCALE,
198                               overall_rect.height / PANGO_SCALE);
199
200           gdk_pango_free_gc (context, bg_gc);
201         }
202
203       gdk_draw_glyphs (drawable, fg_gc, run->item->analysis.font,
204                       x + x_off / PANGO_SCALE, y, run->glyphs);
205
206       switch (uline)
207         {
208         case PANGO_UNDERLINE_NONE:
209           break;
210         case PANGO_UNDERLINE_DOUBLE:
211           gdk_draw_line (drawable, fg_gc,
212                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + 4,
213                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + 4);
214           /* Fall through */
215         case PANGO_UNDERLINE_SINGLE:
216           gdk_draw_line (drawable, fg_gc,
217                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + 2,
218                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + 2);
219           break;
220         case PANGO_UNDERLINE_LOW:
221           gdk_draw_line (drawable, fg_gc,
222                          x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 2,
223                          x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 2);
224           break;
225         }
226
227       if (fg_set)
228         gdk_pango_free_gc (context, fg_gc);
229       
230       x_off += logical_rect.width;
231     }
232 }
233
234 /**
235  * gdk_draw_layout:
236  * @drawable:  the drawable on which to draw string
237  * @gc:        base graphics context to use
238  * @x:         the X position of the left of the layout (in pixels)
239  * @y:         the Y position of the top of the layout (in pixels)
240  * @layout:    a #PangoLayout
241  *
242  * Render a #PangoLayout onto a GDK drawable
243  */
244 void 
245 gdk_draw_layout (GdkDrawable     *drawable,
246                  GdkGC           *gc,
247                  int              x, 
248                  int              y,
249                  PangoLayout     *layout)
250 {
251   PangoRectangle logical_rect;
252   GSList *tmp_list;
253   PangoAlignment align;
254   gint indent;
255   gint width;
256   gint y_offset = 0;
257   gboolean first = FALSE;
258   
259   g_return_if_fail (drawable != NULL);
260   g_return_if_fail (gc != NULL);
261   g_return_if_fail (layout != NULL);
262
263   if (GDK_DRAWABLE_DESTROYED (drawable))
264     return;
265
266   g_return_if_fail (layout != NULL);
267
268   indent = pango_layout_get_indent (layout);
269   width = pango_layout_get_width (layout);
270   align = pango_layout_get_alignment (layout);
271
272   if (width == -1 && align != PANGO_ALIGN_LEFT)
273     {
274       pango_layout_get_extents (layout, NULL, &logical_rect);
275       width = logical_rect.width;
276     }
277   
278   tmp_list = pango_layout_get_lines (layout);
279   while (tmp_list)
280     {
281       PangoLayoutLine *line = tmp_list->data;
282       int x_offset;
283       
284       pango_layout_line_get_extents (line, NULL, &logical_rect);
285
286       if (width != 1 && align == PANGO_ALIGN_RIGHT)
287         x_offset = width - logical_rect.width;
288       else if (width != 1 && align == PANGO_ALIGN_CENTER)
289         x_offset = (width - logical_rect.width) / 2;
290       else
291         x_offset = 0;
292
293       if (first)
294         {
295           if (indent > 0)
296             {
297               if (align == PANGO_ALIGN_LEFT)
298                 x_offset += indent;
299               else
300                 x_offset -= indent;
301             }
302
303           first = FALSE;
304         }
305       else
306         {
307           if (indent < 0)
308             {
309               if (align == PANGO_ALIGN_LEFT)
310                 x_offset -= indent;
311               else
312                 x_offset += indent;
313             }
314         }
315           
316       gdk_draw_layout_line (drawable, gc,
317                             x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
318                             line);
319
320       y_offset += logical_rect.height;
321       tmp_list = tmp_list->next;
322     }
323 }
324
325 static void
326 gdk_pango_get_item_properties (PangoItem      *item,
327                                PangoUnderline *uline,
328                                PangoAttrColor *fg_color,
329                                gboolean       *fg_set,
330                                PangoAttrColor *bg_color,
331                                gboolean       *bg_set)
332 {
333   GSList *tmp_list = item->extra_attrs;
334
335   if (fg_set)
336     *fg_set = FALSE;
337   
338   if (bg_set)
339     *bg_set = FALSE;
340   
341   while (tmp_list)
342     {
343       PangoAttribute *attr = tmp_list->data;
344
345       switch (attr->klass->type)
346         {
347         case PANGO_ATTR_UNDERLINE:
348           if (uline)
349             *uline = ((PangoAttrInt *)attr)->value;
350           break;
351           
352         case PANGO_ATTR_FOREGROUND:
353           if (fg_color)
354             *fg_color = *((PangoAttrColor *)attr);
355           if (fg_set)
356             *fg_set = TRUE;
357           
358           break;
359           
360         case PANGO_ATTR_BACKGROUND:
361           if (bg_color)
362             *bg_color = *((PangoAttrColor *)attr);
363           if (bg_set)
364             *bg_set = TRUE;
365           
366           break;
367           
368         default:
369           break;
370         }
371       tmp_list = tmp_list->next;
372     }
373 }
374