1 /* pangox.c: Routines for handling X fonts
3 * Copyright (C) 1999 Red Hat Software
4 * Copyright (C) 2000 SuSE Linux Ltd
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
28 #include "pango-impl-utils.h"
30 #undef PANGO_DISABLE_DEPRECATED
33 #include "pangox-private.h"
35 #define PANGO_TYPE_X_FONT (pango_x_font_get_type ())
36 #define PANGO_X_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_X_FONT, PangoXFont))
37 #define PANGO_X_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_X_FONT, PangoXFontClass))
38 #define PANGO_X_IS_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_X_FONT))
39 #define PANGO_X_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_X_FONT))
40 #define PANGO_X_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_X_FONT, PangoXFontClass))
42 typedef struct _PangoXFontClass PangoXFontClass;
43 typedef struct _PangoXMetricsInfo PangoXMetricsInfo;
44 typedef struct _PangoXContextInfo PangoXContextInfo;
46 struct _PangoXSubfontInfo
49 XFontStruct *font_struct;
55 struct _PangoXMetricsInfo
57 const char *sample_str;
58 PangoFontMetrics *metrics;
61 struct _PangoXContextInfo
63 PangoGetGCFunc get_gc_func;
64 PangoFreeGCFunc free_gc_func;
67 struct _PangoXFontClass
69 PangoFontClass parent_class;
72 static PangoFontClass *parent_class; /* Parent class structure for PangoXFont */
74 static void pango_x_font_class_init (PangoXFontClass *class);
75 static void pango_x_font_init (PangoXFont *xfont);
76 static void pango_x_font_dispose (GObject *object);
77 static void pango_x_font_finalize (GObject *object);
79 static PangoFontDescription *pango_x_font_describe (PangoFont *font);
80 static PangoCoverage * pango_x_font_get_coverage (PangoFont *font,
81 PangoLanguage *language);
82 static PangoEngineShape * pango_x_font_find_shaper (PangoFont *font,
83 PangoLanguage *language,
85 static void pango_x_font_get_glyph_extents (PangoFont *font,
87 PangoRectangle *ink_rect,
88 PangoRectangle *logical_rect);
89 static PangoFontMetrics * pango_x_font_get_metrics (PangoFont *font,
90 PangoLanguage *language);
91 static PangoFontMap * pango_x_font_get_font_map (PangoFont *font);
93 static PangoXSubfontInfo * pango_x_find_subfont (PangoFont *font,
94 PangoXSubfont subfont_index);
95 static XCharStruct * pango_x_get_per_char (PangoFont *font,
96 PangoXSubfontInfo *subfont,
98 static gboolean pango_x_find_glyph (PangoFont *font,
100 PangoXSubfontInfo **subfont_return,
101 XCharStruct **charstruct_return);
102 static XFontStruct * pango_x_get_font_struct (PangoFont *font,
103 PangoXSubfontInfo *info);
105 static void pango_x_get_item_properties (PangoItem *item,
106 PangoUnderline *uline,
107 PangoAttrColor *fg_color,
109 PangoAttrColor *bg_color,
112 static inline PangoXSubfontInfo *
113 pango_x_find_subfont (PangoFont *font,
114 PangoXSubfont subfont_index)
116 PangoXFont *xfont = (PangoXFont *)font;
118 if (subfont_index < 1 || subfont_index > xfont->n_subfonts)
121 return xfont->subfonts[subfont_index-1];
125 pango_x_make_font_struct (PangoFont *font, PangoXSubfontInfo *info)
127 PangoXFont *xfont = (PangoXFont *)font;
128 PangoXFontCache *cache;
130 cache = pango_x_font_map_get_font_cache (xfont->fontmap);
132 info->font_struct = pango_x_font_cache_load (cache, info->xlfd);
133 if (!info->font_struct)
135 g_warning ("Cannot load font for XLFD '%s\n", info->xlfd);
137 /* Prevent a segfault, but probably not much more */
138 info->font_struct = pango_x_font_cache_load (cache, "fixed");
141 info->is_1byte = (info->font_struct->min_byte1 == 0 && info->font_struct->max_byte1 == 0);
142 info->range_byte1 = info->font_struct->max_byte1 - info->font_struct->min_byte1 + 1;
143 info->range_byte2 = info->font_struct->max_char_or_byte2 - info->font_struct->min_char_or_byte2 + 1;
146 static inline XFontStruct *
147 pango_x_get_font_struct (PangoFont *font, PangoXSubfontInfo *info)
149 if (!info->font_struct)
150 pango_x_make_font_struct (font, info);
152 return info->font_struct;
156 free_context_info (PangoXContextInfo *info)
158 g_slice_free (PangoXContextInfo, info);
161 static PangoXContextInfo *
162 get_context_info (PangoContext *context)
164 PangoXContextInfo *info;
165 static GQuark quark = 0;
167 if (G_UNLIKELY (!quark))
168 quark = g_quark_from_static_string ("pango-x-info");
170 info = g_object_get_qdata (G_OBJECT (context), quark);
172 if (G_UNLIKELY (!info))
174 info = g_slice_new (PangoXContextInfo);
175 info->get_gc_func = NULL;
176 info->free_gc_func = NULL;
177 g_object_set_qdata_full (G_OBJECT (context),
179 info, (GDestroyNotify)free_context_info);
186 * pango_x_get_context:
187 * @display: an X display (As returned by XOpenDisplay().)
189 * Retrieves a #PangoContext appropriate for rendering with X fonts on the
192 * Return value: the new #PangoContext.
194 * Deprecated: 1.22: Use pango_x_font_map_for_display() followed by
195 * pango_font_map_create_context() instead.
198 pango_x_get_context (Display *display)
200 return pango_font_map_create_context (pango_x_font_map_for_display (display));
204 * pango_x_context_set_funcs:
205 * @context: a #PangoContext.
206 * @get_gc_func: function called to create a new GC for a given color.
207 * @free_gc_func: function called to free a GC created with @get_gc_func.
209 * Sets the functions that will be used to get GC's in various colors when
210 * rendering layouts with this context.
213 pango_x_context_set_funcs (PangoContext *context,
214 PangoGetGCFunc get_gc_func,
215 PangoFreeGCFunc free_gc_func)
217 PangoXContextInfo *info;
219 g_return_if_fail (context != NULL);
221 info = get_context_info (context);
223 info->get_gc_func = get_gc_func;
224 info->free_gc_func = free_gc_func;
228 pango_x_font_get_type (void)
230 static GType object_type = 0;
232 if (G_UNLIKELY (!object_type))
234 const GTypeInfo object_info =
236 sizeof (PangoXFontClass),
237 (GBaseInitFunc) NULL,
238 (GBaseFinalizeFunc) NULL,
239 (GClassInitFunc) pango_x_font_class_init,
240 NULL, /* class_finalize */
241 NULL, /* class_data */
244 (GInstanceInitFunc) pango_x_font_init,
245 NULL /* value_table */
248 object_type = g_type_register_static (PANGO_TYPE_FONT,
257 pango_x_font_init (PangoXFont *xfont)
259 xfont->subfonts_by_charset = g_hash_table_new (g_str_hash, g_str_equal);
261 xfont->n_subfonts = 0;
262 xfont->max_subfonts = 1;
264 xfont->subfonts = g_new (PangoXSubfontInfo *, xfont->max_subfonts);
266 xfont->metrics_by_lang = NULL;
273 pango_x_font_class_init (PangoXFontClass *class)
275 GObjectClass *object_class = G_OBJECT_CLASS (class);
276 PangoFontClass *font_class = PANGO_FONT_CLASS (class);
278 parent_class = g_type_class_peek_parent (class);
280 object_class->finalize = pango_x_font_finalize;
281 object_class->dispose = pango_x_font_dispose;
283 font_class->describe = pango_x_font_describe;
284 font_class->get_coverage = pango_x_font_get_coverage;
285 font_class->find_shaper = pango_x_font_find_shaper;
286 font_class->get_glyph_extents = pango_x_font_get_glyph_extents;
287 font_class->get_metrics = pango_x_font_get_metrics;
288 font_class->get_font_map = pango_x_font_get_font_map;
292 pango_x_font_new (PangoFontMap *fontmap, const char *spec, int size)
296 g_return_val_if_fail (fontmap != NULL, NULL);
297 g_return_val_if_fail (spec != NULL, NULL);
299 result = g_object_new (PANGO_TYPE_X_FONT, NULL);
301 g_assert (result->fontmap == NULL);
302 result->fontmap = fontmap;
303 g_object_add_weak_pointer (G_OBJECT (result->fontmap), (gpointer *) (gpointer) &result->fontmap);
305 result->display = pango_x_fontmap_get_display (fontmap);
307 result->fonts = g_strsplit(spec, ",", -1);
308 for (result->n_fonts = 0; result->fonts[result->n_fonts]; result->n_fonts++)
318 * @display: the X display.
319 * @spec: a comma-separated list of XLFD's.
321 * Loads up a logical font based on a "fontset" style text
322 * specification. This is not remotely useful (Pango API's generally
323 * work in terms of #PangoFontDescription) and the result may not
324 * work correctly in all circumstances. Use of this function should
327 * Returns: a new #PangoFont.
330 pango_x_load_font (Display *display,
335 g_return_val_if_fail (display != NULL, NULL);
336 g_return_val_if_fail (spec != NULL, NULL);
338 result = pango_x_font_new (pango_x_font_map_for_display (display), spec, -1);
340 return (PangoFont *)result;
348 XDrawString16 (display, d, gc, \
349 glyph_x0, glyph_y0, \
350 xcharbuffer, charcount); \
358 * @display: the X display.
359 * @d: the drawable on which to draw string.
360 * @gc: the graphics context.
361 * @font: the font in which to draw the string.
362 * @glyphs: the glyph string to draw.
363 * @x: the x position of start of string (in pixels).
364 * @y: the y position of baseline (in pixels).
366 * Renders a #PangoGlyphString onto an X drawable.
369 pango_x_render (Display *display,
373 PangoGlyphString *glyphs,
383 * We collect the characters in this buffer as long as the font does not
384 * change. At that time, or when the buffer runs full, or at the end,
385 * then we empty the buffer.
387 XChar2b xcharbuffer[1000];
388 int glyph_x0 = 0, expected_x = 0; /* x/y initializations are to quiet GCC */
392 g_return_if_fail (display != NULL);
393 g_return_if_fail (glyphs != NULL);
395 for (i=0; i<glyphs->num_glyphs; i++)
397 PangoGlyph glyph = glyphs->glyphs[i].glyph;
398 int glyph_x = x + PANGO_PIXELS (x_off + glyphs->glyphs[i].geometry.x_offset);
399 int glyph_y = y + PANGO_PIXELS (glyphs->glyphs[i].geometry.y_offset);
401 /* Clip glyphs into the X coordinate range; we really
402 * want to clip glyphs with an ink rect outside the
403 * [0,32767] x [0,32767] rectangle but looking up
404 * the ink rect here would be a noticeable speed hit.
405 * This is close enough.
407 if (!(glyph != PANGO_GLYPH_EMPTY &&
408 glyph_x >= -16384 && glyph_x <= 32767 &&
409 glyph_y >= -16384 && glyph_y <= 32767))
412 if (G_LIKELY ((glyph & PANGO_GLYPH_UNKNOWN_FLAG) == 0))
414 guint16 index = PANGO_X_GLYPH_INDEX (glyph);
415 guint16 subfont_index = PANGO_X_GLYPH_SUBFONT (glyph);
416 PangoXSubfontInfo *subfont;
418 subfont = pango_x_find_subfont (font, subfont_index);
421 fs = pango_x_get_font_struct (font, subfont);
425 if (fs->fid != old_fid)
428 XSetFont (display, gc, fs->fid);
432 if (charcount == G_N_ELEMENTS (xcharbuffer) ||
433 (charcount > 0 && (glyph_y != glyph_y0 ||
434 glyph_x != expected_x)))
442 xcharbuffer[charcount].byte1 = index / 256;
443 xcharbuffer[charcount].byte2 = index % 256;
445 expected_x = glyph_x + XTextWidth16 (fs, &xcharbuffer[charcount], 1);
451 PangoFontMetrics *metrics;
452 int x1, y1, x2, y2; /* rectangle the character should go inside. */
456 gboolean invalid_input;
462 metrics = pango_font_get_metrics (font, NULL);
468 y1 = glyph_y - PANGO_PIXELS (metrics->ascent);
469 y2 = y1 + PANGO_PIXELS (metrics->ascent + metrics->descent);
474 y1 = y2 - PANGO_UNKNOWN_GLYPH_HEIGHT;
478 x2 = x1 + PANGO_PIXELS (glyphs->glyphs[i].geometry.width);
481 stroke_thick = MAX ((int) (0.5 + 0.025 * (y2 - y1)), 1);
483 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
484 wc = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
487 invalid_input = glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF;
493 case 0x2028: /* Line separator */
494 case 0x2029: /* Paragraph separator */
496 /* Draw a carriage-return thingy */
497 PangoRectangle up_stroke;
498 PangoRectangle across_stroke;
500 int hborder = (x2 - x1) * 0.1;
501 int arrow_height = 0.25 * (y2 - y1);
502 int top_border = (y2 - y1) * 0.25;
504 int arrow_x, arrow_width, tmp_height;
506 /* Draw the arrow-head */
508 tmp_height = (stroke_thick % 2 == 0) ? 2 : 1; /* Starting height */
509 arrow_height = 2 * ((1 + arrow_height - tmp_height) / 2) + tmp_height; /* Force symmetry */
510 arrow_width = 2 + arrow_height - tmp_height;
512 for (arrow_x = x1 + hborder; arrow_x < x1 + hborder + arrow_width; arrow_x++)
514 XDrawLine (display, d, gc,
516 baseline - stroke_thick + (stroke_thick - tmp_height) / 2,
518 baseline - stroke_thick + (stroke_thick - tmp_height) / 2 + tmp_height - 1);
520 if ((arrow_x - x1 - hborder) % 2 == 1)
524 across_stroke.x = arrow_x;
525 across_stroke.width = x2 - hborder - arrow_x - stroke_thick;
526 across_stroke.y = baseline - stroke_thick;
527 across_stroke.height = stroke_thick;
529 XFillRectangle (display, d, gc,
530 across_stroke.x, across_stroke.y,
531 across_stroke.width, across_stroke.height);
533 up_stroke.x = across_stroke.x + across_stroke.width;
534 up_stroke.width = stroke_thick;
535 up_stroke.y = y1 + top_border;
536 up_stroke.height = baseline - up_stroke.y;
538 XFillRectangle (display, d, gc,
539 up_stroke.x, up_stroke.y,
540 up_stroke.width, up_stroke.height);
546 /* Perhaps we should draw the box-with-numbers as in the
547 * other backends, though we have no guarantee of having
548 * an appropriate size of font. Right now, we just
549 * draw an empty box. (To draw the box-with-numbers.
550 * the backends would have to be changed to use
551 * pango_x_font_get_unknown_glyph() rather than
552 * pango_x_get_unknown_glyph().
555 int xspace = MAX ((int) (0.5 + 0.1 * (x2 - x1)), 1);
556 int yspace = MAX ((int) (0.5 + 0.1 * (y2 - y1)), 1);
563 XFillRectangle (display, d, gc,
565 x2 - x1, stroke_thick);
566 XFillRectangle (display, d, gc,
567 x1, y1 + stroke_thick,
568 stroke_thick, y2 - y1 - 2 * stroke_thick);
569 XFillRectangle (display, d, gc,
570 x2 - stroke_thick, y1 + stroke_thick,
571 stroke_thick, y2 - y1 - 2 * stroke_thick);
572 XFillRectangle (display, d, gc,
573 x1, y2 - stroke_thick,
574 x2 - x1, stroke_thick);
577 XDrawLine (display, d, gc,
580 XDrawLine (display, d, gc,
589 pango_font_metrics_unref (metrics);
593 x_off += glyphs->glyphs[i].geometry.width;
601 pango_x_font_get_glyph_extents (PangoFont *font,
603 PangoRectangle *ink_rect,
604 PangoRectangle *logical_rect)
607 PangoXSubfontInfo *subfont;
609 if (glyph == PANGO_GLYPH_EMPTY)
612 ink_rect->x = ink_rect->width = ink_rect->y = ink_rect->height = 0;
614 logical_rect->x = logical_rect->width = logical_rect->y = logical_rect->height = 0;
617 if ((glyph & PANGO_GLYPH_UNKNOWN_FLAG) == 0 && pango_x_find_glyph (font, glyph, &subfont, &cs))
621 ink_rect->x = PANGO_SCALE * cs->lbearing;
622 ink_rect->width = PANGO_SCALE * (cs->rbearing - cs->lbearing);
623 ink_rect->y = PANGO_SCALE * -cs->ascent;
624 ink_rect->height = PANGO_SCALE * (cs->ascent + cs->descent);
629 logical_rect->width = PANGO_SCALE * cs->width;
630 logical_rect->y = - PANGO_SCALE * subfont->font_struct->ascent;
631 logical_rect->height = PANGO_SCALE * (subfont->font_struct->ascent + subfont->font_struct->descent);
636 PangoFontMetrics *metrics;
638 gdouble width_factor;
641 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
642 wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
650 case 0x2028: /* Line separator */
651 case 0x2029: /* Paragraph separator */
653 #define MAGIC_FACTOR 1.2
655 /* carriage-return thingy */
656 width_factor = MAGIC_FACTOR;
661 /* Unknown glyph square */
666 metrics = pango_font_get_metrics (font, NULL);
670 w = metrics->approximate_char_width * width_factor;
671 w = PANGO_SCALE * PANGO_PIXELS (w);
675 ink_rect->x = PANGO_SCALE;
676 ink_rect->width = w - 2 * PANGO_SCALE;
677 ink_rect->y = - (metrics->ascent - PANGO_SCALE);
678 ink_rect->height = metrics->ascent + metrics->descent - 2 * PANGO_SCALE;
683 logical_rect->width = w;
684 logical_rect->y = - metrics->ascent;
685 logical_rect->height = metrics->ascent + metrics->descent;
688 pango_font_metrics_unref (metrics);
693 ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
695 logical_rect->x = logical_rect->y = logical_rect->height = logical_rect->width = 0;
701 get_int_prop (Atom atom,
710 while (i < fs->n_properties)
712 if (fs->properties[i].name == atom)
714 *val = fs->properties[i].card32;
724 /* Call @func with each glyph resulting from shaping @string with each
725 * glyph. This duplicates quite a bit of code from pango_itemize. This
726 * function should die and we should simply add the ability to specify
727 * particular fonts when itemizing.
730 itemize_string_foreach (PangoFont *font,
731 PangoLanguage *language,
733 void (*func) (PangoFont *font,
734 PangoGlyphInfo *glyph_info,
738 const char *start, *p;
739 PangoGlyphString *glyph_str = pango_glyph_string_new ();
740 PangoEngineShape *shaper, *last_shaper;
743 guint8 *embedding_levels;
744 PangoDirection base_dir = PANGO_DIRECTION_LTR;
745 gboolean finished = FALSE;
747 embedding_levels = pango_log2vis_get_embedding_levels (str, -1, &base_dir);
754 while (*p || !finished)
760 wc = g_utf8_get_char (p);
761 shaper = pango_font_find_shaper (font, language, wc);
771 (shaper != last_shaper || last_level != embedding_levels[i])))
773 PangoAnalysis analysis = { NULL };
776 analysis.shape_engine = last_shaper;
777 analysis.font = font;
778 analysis.language = language;
779 analysis.level = last_level;
781 pango_shape (start, p - start, &analysis, glyph_str);
783 for (j = 0; j < glyph_str->num_glyphs; j++)
784 (*func) (font, &glyph_str->glyphs[j], data);
791 p = g_utf8_next_char (p);
793 last_shaper = shaper;
794 last_level = embedding_levels[i];
799 pango_glyph_string_free (glyph_str);
800 g_free (embedding_levels);
803 /* Get composite font metrics for all subfonts in list
806 get_font_metrics_from_subfonts (PangoFont *font,
808 PangoFontMetrics *metrics)
810 PangoXFont *xfont = (PangoXFont *)font;
811 GSList *tmp_list = subfonts;
812 gboolean first = TRUE;
813 int total_avg_widths = 0;
814 int n_avg_widths = 0;
817 avg_width_atom = pango_x_fontmap_atom_from_name (xfont->fontmap,
821 metrics->descent = 0;
825 PangoXSubfontInfo *subfont = pango_x_find_subfont (font, GPOINTER_TO_UINT (tmp_list->data));
829 XFontStruct *fs = pango_x_get_font_struct (font, subfont);
836 metrics->ascent = fs->ascent * PANGO_SCALE;
837 metrics->descent = fs->descent * PANGO_SCALE;
842 metrics->ascent = MAX (fs->ascent * PANGO_SCALE, metrics->ascent);
843 metrics->descent = MAX (fs->descent * PANGO_SCALE, metrics->descent);
846 if (get_int_prop (avg_width_atom, fs, &avg_width))
848 /* convert decipoints --> Pango units.
849 * Resolution is in (points * PANGO_SCALE) / pixel,
850 * avg_width in decipoints.
851 * We want pixels * PANGO_SCALE
854 /* Convert to points * PANGO_SCALE */
855 avg_width *= PANGO_SCALE / (double) 10.0;
856 /* Convert to pixels * PANGO_SCALE */
857 avg_width *= (PANGO_SCALE / PANGO_X_FONT_MAP (PANGO_X_FONT (font)->fontmap)->resolution);
861 avg_width = PANGO_SCALE * ((fs->min_bounds.width + fs->max_bounds.width) / 2);
867 total_avg_widths += avg_width;
872 g_warning ("Invalid subfont %d in get_font_metrics_from_subfonts", GPOINTER_TO_UINT (tmp_list->data));
874 tmp_list = tmp_list->next;
877 /* This is pretty darn bogus. */
879 metrics->approximate_char_width = total_avg_widths / n_avg_widths;
881 metrics->approximate_char_width = PANGO_UNKNOWN_GLYPH_WIDTH * PANGO_SCALE;
882 if (metrics->ascent + metrics->descent == 0)
884 metrics->ascent = PANGO_UNKNOWN_GLYPH_HEIGHT * PANGO_SCALE;
885 metrics->descent = 0;
890 get_subfonts_foreach (PangoFont *font,
891 PangoGlyphInfo *glyph_info,
894 GSList **subfonts = data;
895 PangoGlyph glyph = glyph_info->glyph;
896 PangoXSubfont subfont;
898 if (glyph == PANGO_GLYPH_EMPTY)
901 /* Use an arbitrary subfont for unknown glyphs...*/
902 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
904 if (((PangoXFont *)font)->n_subfonts > 0)
905 glyph = PANGO_X_MAKE_GLYPH (1, 0);
910 subfont = PANGO_X_GLYPH_SUBFONT (glyph);
911 if (!g_slist_find (*subfonts, GUINT_TO_POINTER ((guint)subfont)))
912 *subfonts = g_slist_prepend (*subfonts, GUINT_TO_POINTER ((guint)subfont));
915 /* Get composite font metrics for all subfonts resulting from shaping
916 * string str with the given font
919 get_font_metrics_from_string (PangoFont *font,
920 PangoLanguage *language,
922 PangoFontMetrics *metrics)
924 GSList *subfonts = NULL;
926 itemize_string_foreach (font, language, str, get_subfonts_foreach, &subfonts);
927 get_font_metrics_from_subfonts (font, subfonts, metrics);
928 g_slist_free (subfonts);
932 average_width_foreach (PangoFont *font G_GNUC_UNUSED,
933 PangoGlyphInfo *glyph_info,
938 *width += glyph_info->geometry.width;
941 /* Get composite font metrics for all subfonts resulting from shaping
942 * string str with the given font
945 get_total_width_for_string (PangoFont *font,
946 PangoLanguage *language,
951 itemize_string_foreach (font, language, str, average_width_foreach, &width);
956 static PangoFontMetrics *
957 pango_x_font_get_metrics (PangoFont *font,
958 PangoLanguage *language)
960 PangoXMetricsInfo *info = NULL; /* Quiet gcc */
961 PangoXFont *xfont = (PangoXFont *)font;
964 const char *sample_str = pango_language_get_sample_string (language);
966 tmp_list = xfont->metrics_by_lang;
969 info = tmp_list->data;
971 if (info->sample_str == sample_str) /* We _don't_ need strcmp */
974 tmp_list = tmp_list->next;
979 PangoFontMetrics *metrics;
981 info = g_slice_new0 (PangoXMetricsInfo);
983 xfont->metrics_by_lang = g_slist_prepend (xfont->metrics_by_lang, info);
985 info->sample_str = sample_str;
986 metrics = pango_font_metrics_new ();
988 get_font_metrics_from_string (font, language, sample_str, metrics);
990 metrics->approximate_digit_width = get_total_width_for_string (font, language, "0123456789") / 10;
992 info->metrics = metrics;
995 return pango_font_metrics_ref (info->metrics);
998 static PangoFontMap *
999 pango_x_font_get_font_map (PangoFont *font)
1001 PangoXFont *xfont = (PangoXFont *)font;
1003 return xfont->fontmap;
1006 /* Compare the tail of a to b */
1008 match_end (const char *a, const char *b)
1010 size_t len_a = strlen (a);
1011 size_t len_b = strlen (b);
1016 return (strcmp (a + len_a - len_b, b) == 0);
1019 /* Substitute in a charset into an XLFD. Return the
1020 * (g_malloc'd) new name, or %NULL if the XLFD cannot
1024 name_for_charset (char *xlfd, char *charset)
1027 char *dash_charset = g_strconcat ("-", charset, NULL);
1028 char *result = NULL;
1031 for (p = xlfd; *p; p++)
1035 if (ndashes == 14) /* Complete XLFD */
1037 if (match_end (xlfd, "-*-*"))
1039 result = g_malloc (strlen (xlfd) - 4 + strlen (dash_charset) + 1);
1040 strncpy (result, xlfd, strlen (xlfd) - 4);
1041 strcpy (result + strlen (xlfd) - 4, dash_charset);
1043 if (match_end (xlfd, dash_charset))
1044 result = g_strdup (xlfd);
1046 else if (ndashes == 13)
1048 if (match_end (xlfd, "-*"))
1050 result = g_malloc (strlen (xlfd) - 2 + strlen (dash_charset) + 1);
1051 strncpy (result, xlfd, strlen (xlfd) - 2);
1052 strcpy (result + strlen (xlfd) - 2, dash_charset);
1054 if (match_end (xlfd, dash_charset))
1055 result = g_strdup (xlfd);
1059 if (match_end (xlfd, "*"))
1061 result = g_malloc (strlen (xlfd) + strlen (dash_charset) + 1);
1062 strcpy (result, xlfd);
1063 strcpy (result + strlen (xlfd), dash_charset);
1065 if (match_end (xlfd, dash_charset))
1066 result = g_strdup (xlfd);
1069 g_free (dash_charset);
1073 static PangoXSubfont
1074 pango_x_insert_subfont (PangoFont *font, const char *xlfd)
1076 PangoXFont *xfont = (PangoXFont *)font;
1077 PangoXSubfontInfo *info;
1079 info = g_slice_new (PangoXSubfontInfo);
1081 info->xlfd = g_strdup (xlfd);
1082 info->font_struct = NULL;
1084 xfont->n_subfonts++;
1086 if (xfont->n_subfonts > xfont->max_subfonts)
1088 xfont->max_subfonts *= 2;
1089 xfont->subfonts = g_renew (PangoXSubfontInfo *, xfont->subfonts, xfont->max_subfonts);
1092 xfont->subfonts[xfont->n_subfonts - 1] = info;
1094 return xfont->n_subfonts;
1098 * pango_x_list_subfonts:
1099 * @font: a #PangoFont.
1100 * @charsets: the charsets to list subfonts for.
1101 * @n_charsets: the number of charsets in @charsets.
1102 * @subfont_ids: location to store a pointer to an array of subfont IDs for each found subfont;
1103 * the result must be freed using g_free().
1104 * @subfont_charsets: location to store a pointer to an array of subfont IDs for each found subfont;
1105 * the result must be freed using g_free().
1107 * Lists the subfonts of a given font. The result is ordered first by charset,
1108 * and then within each charset, by the order of fonts in the font specification.
1110 * Return value: length of the arrays stored in @subfont_ids and
1111 * @subfont_charsets.
1114 pango_x_list_subfonts (PangoFont *font,
1117 PangoXSubfont **subfont_ids,
1118 int **subfont_charsets)
1120 PangoXFont *xfont = (PangoXFont *)font;
1121 PangoXSubfont **subfont_lists;
1122 PangoFontMap *fontmap;
1126 g_return_val_if_fail (font != NULL, 0);
1127 g_return_val_if_fail (n_charsets == 0 || charsets != NULL, 0);
1129 fontmap = pango_x_font_map_for_display (xfont->display);
1131 subfont_lists = g_new (PangoXSubfont *, n_charsets);
1133 for (j=0; j<n_charsets; j++)
1135 subfont_lists[j] = g_hash_table_lookup (xfont->subfonts_by_charset, charsets[j]);
1136 if (!subfont_lists[j])
1138 subfont_lists[j] = g_new (PangoXSubfont, xfont->n_fonts);
1140 for (i = 0; i < xfont->n_fonts; i++)
1142 PangoXSubfont subfont = 0;
1145 if (xfont->size == -1)
1147 xlfd = name_for_charset (xfont->fonts[i], charsets[j]);
1152 char **names = XListFonts (xfont->display, xlfd, 1, &count);
1154 subfont = pango_x_insert_subfont (font, names[0]);
1156 XFreeFontNames (names);
1162 xlfd = pango_x_make_matching_xlfd (fontmap, xfont->fonts[i], charsets[j], xfont->size);
1165 subfont = pango_x_insert_subfont (font, xlfd);
1170 subfont_lists[j][i] = subfont;
1173 g_hash_table_insert (xfont->subfonts_by_charset, g_strdup (charsets[j]), subfont_lists[j]);
1176 for (i = 0; i < xfont->n_fonts; i++)
1177 if (subfont_lists[j][i])
1181 *subfont_ids = g_new (PangoXSubfont, n_subfonts);
1182 *subfont_charsets = g_new (int, n_subfonts);
1186 for (j=0; j<n_charsets; j++)
1187 for (i=0; i<xfont->n_fonts; i++)
1188 if (subfont_lists[j][i])
1190 (*subfont_ids)[n_subfonts] = subfont_lists[j][i];
1191 (*subfont_charsets)[n_subfonts] = j;
1195 g_free (subfont_lists);
1201 * pango_x_has_glyph:
1202 * @font: a #PangoFont which must be from the X backend.
1203 * @glyph: the index of a glyph in the font. (Formed
1204 * using the #PANGO_X_MAKE_GLYPH macro)
1206 * Checks if the given glyph is present in a X font.
1208 * Return value: %TRUE if the glyph is present.
1211 pango_x_has_glyph (PangoFont *font,
1214 PangoXSubfontInfo *subfont;
1217 guint16 char_index = PANGO_X_GLYPH_INDEX (glyph);
1218 guint16 subfont_index = PANGO_X_GLYPH_SUBFONT (glyph);
1220 subfont = pango_x_find_subfont (font, subfont_index);
1224 cs = pango_x_get_per_char (font, subfont, char_index);
1226 if (cs && (cs->lbearing != cs->rbearing || cs->width != 0))
1233 * pango_x_font_subfont_xlfd:
1234 * @font: a #PangoFont which must be from the X backend.
1235 * @subfont_id: the id of a subfont within the font.
1237 * Determines the X Logical Font Description for the specified
1240 * Return value: A newly-allocated string containing the XLFD for the
1241 * subfont. This string must be freed with g_free().
1244 pango_x_font_subfont_xlfd (PangoFont *font,
1245 PangoXSubfont subfont_id)
1247 PangoXSubfontInfo *subfont;
1249 g_return_val_if_fail (font != NULL, NULL);
1250 g_return_val_if_fail (PANGO_X_IS_FONT (font), NULL);
1252 subfont = pango_x_find_subfont (font, subfont_id);
1255 g_warning ("pango_x_font_subfont_xlfd: Invalid subfont_id specified");
1259 return g_strdup (subfont->xlfd);
1263 pango_x_font_dispose (GObject *object)
1265 PangoXFont *xfont = PANGO_X_FONT (object);
1267 /* If the font is not already in the freed-fonts cache, add it,
1268 * if it is already there, do nothing and the font will be
1271 if (!xfont->in_cache && xfont->fontmap)
1272 pango_x_fontmap_cache_add (xfont->fontmap, xfont);
1274 G_OBJECT_CLASS (parent_class)->dispose (object);
1279 subfonts_foreach (gpointer key, gpointer value, gpointer data G_GNUC_UNUSED)
1286 free_metrics_info (PangoXMetricsInfo *info)
1288 pango_font_metrics_unref (info->metrics);
1289 g_slice_free (PangoXMetricsInfo, info);
1293 pango_x_font_finalize (GObject *object)
1295 PangoXFont *xfont = (PangoXFont *)object;
1296 PangoXFontCache *cache = pango_x_font_map_get_font_cache (xfont->fontmap);
1300 for (i=0; i<xfont->n_subfonts; i++)
1302 PangoXSubfontInfo *info = xfont->subfonts[i];
1304 g_free (info->xlfd);
1306 if (info->font_struct)
1307 pango_x_font_cache_unload (cache, info->font_struct);
1309 g_slice_free (PangoXSubfontInfo, info);
1312 g_free (xfont->subfonts);
1314 g_hash_table_foreach (xfont->subfonts_by_charset, subfonts_foreach, NULL);
1315 g_hash_table_destroy (xfont->subfonts_by_charset);
1317 g_slist_foreach (xfont->metrics_by_lang, (GFunc)free_metrics_info, NULL);
1318 g_slist_free (xfont->metrics_by_lang);
1321 pango_x_face_remove (xfont->xface, (PangoFont *)xfont);
1323 g_assert (xfont->fontmap != NULL);
1324 g_object_remove_weak_pointer (G_OBJECT (xfont->fontmap), (gpointer *) (gpointer) &xfont->fontmap);
1325 xfont->fontmap = NULL;
1327 g_strfreev (xfont->fonts);
1329 G_OBJECT_CLASS (parent_class)->finalize (object);
1332 static PangoFontDescription *
1333 pango_x_font_describe (PangoFont *font)
1335 /* FIXME: this doesn't work for fonts from pango_x_font_load()
1337 PangoXFont *xfont = (PangoXFont *)font;
1341 PangoFontDescription *desc = pango_font_face_describe (PANGO_FONT_FACE (xfont->xface));
1342 pango_font_description_set_size (desc, xfont->size);
1351 pango_x_get_shaper_map (PangoLanguage *language)
1353 static guint engine_type_id = 0;
1354 static guint render_type_id = 0;
1356 if (engine_type_id == 0)
1358 engine_type_id = g_quark_from_static_string (PANGO_ENGINE_TYPE_SHAPE);
1359 render_type_id = g_quark_from_static_string (PANGO_RENDER_TYPE_X);
1362 return pango_find_map (language, engine_type_id, render_type_id);
1365 static PangoCoverage *
1366 pango_x_font_get_coverage (PangoFont *font,
1367 PangoLanguage *language)
1369 PangoXFont *xfont = (PangoXFont *)font;
1371 return pango_x_face_get_coverage (xfont->xface, font, language);
1374 static PangoEngineShape *
1375 pango_x_font_find_shaper (PangoFont *font G_GNUC_UNUSED,
1376 PangoLanguage *language,
1379 PangoMap *shape_map = NULL;
1382 shape_map = pango_x_get_shaper_map (language);
1383 script = pango_script_for_unichar (ch);
1384 return (PangoEngineShape *)pango_map_get_engine (shape_map, script);
1387 /* Utility functions */
1389 static XCharStruct *
1390 pango_x_get_per_char (PangoFont *font,
1391 PangoXSubfontInfo *subfont,
1400 fs = pango_x_get_font_struct (font, subfont);
1404 if (subfont->is_1byte)
1406 index = (int)char_index - fs->min_char_or_byte2;
1407 if (index < 0 || index >= subfont->range_byte2)
1412 byte1 = (int)(char_index / 256) - fs->min_byte1;
1413 if (byte1 < 0 || byte1 >= subfont->range_byte1)
1416 byte2 = (int)(char_index % 256) - fs->min_char_or_byte2;
1417 if (byte2 < 0 || byte2 >= subfont->range_byte2)
1420 index = byte1 * subfont->range_byte2 + byte2;
1424 return &fs->per_char[index];
1426 return &fs->min_bounds;
1430 pango_x_find_glyph (PangoFont *font,
1432 PangoXSubfontInfo **subfont_return,
1433 XCharStruct **charstruct_return)
1435 PangoXSubfontInfo *subfont;
1438 guint16 char_index = PANGO_X_GLYPH_INDEX (glyph);
1439 guint16 subfont_index = PANGO_X_GLYPH_SUBFONT (glyph);
1441 subfont = pango_x_find_subfont (font, subfont_index);
1445 cs = pango_x_get_per_char (font, subfont, char_index);
1447 if (cs && (cs->lbearing != cs->rbearing || cs->width != 0))
1450 *subfont_return = subfont;
1452 if (charstruct_return)
1453 *charstruct_return = cs;
1462 * pango_x_get_unknown_glyph:
1463 * @font: a #PangoFont.
1465 * Returns the index of a glyph suitable for drawing unknown characters;
1466 * you should generally use PANGO_GET_UNKNOWN_GLYPH() instead,
1467 * since that may return a glyph that provides a better representation
1468 * of a particular char. (E.g., by showing hex digits, or a glyph
1469 * representative of a certain Unicode range.)
1471 * Return value: a glyph index into @font.
1474 pango_x_get_unknown_glyph (PangoFont *font G_GNUC_UNUSED)
1476 return PANGO_GET_UNKNOWN_GLYPH (0);
1480 * pango_x_render_layout_line:
1481 * @display: the X display.
1482 * @drawable: the drawable on which to draw.
1483 * @gc: GC to use for uncolored drawing.
1484 * @line: a #PangoLayoutLine.
1485 * @x: the x position of start of string (in pixels).
1486 * @y: the y position of baseline (in pixels).
1488 * Renders a #PangoLayoutLine onto an X drawable.
1491 pango_x_render_layout_line (Display *display,
1494 PangoLayoutLine *line,
1498 GSList *tmp_list = line->runs;
1499 PangoRectangle overall_rect;
1500 PangoRectangle logical_rect;
1501 PangoRectangle ink_rect;
1502 PangoContext *context = pango_layout_get_context (line->layout);
1503 PangoXContextInfo *info = get_context_info (context);
1507 pango_layout_line_get_extents (line,NULL, &overall_rect);
1511 PangoUnderline uline = PANGO_UNDERLINE_NONE;
1512 PangoLayoutRun *run = tmp_list->data;
1513 PangoAttrColor fg_color, bg_color;
1514 gboolean fg_set, bg_set;
1517 tmp_list = tmp_list->next;
1519 pango_x_get_item_properties (run->item, &uline, &fg_color, &fg_set, &bg_color, &bg_set);
1521 if (fg_set && info->get_gc_func)
1522 fg_gc = info->get_gc_func (context, &fg_color.color, gc);
1526 if (uline == PANGO_UNDERLINE_NONE)
1527 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
1528 NULL, &logical_rect);
1530 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
1531 &ink_rect, &logical_rect);
1533 if (bg_set && info->get_gc_func)
1535 GC bg_gc = info->get_gc_func (context, &bg_color.color, gc);
1537 XFillRectangle (display, drawable, bg_gc,
1538 x + (x_off + logical_rect.x) / PANGO_SCALE,
1539 y + overall_rect.y / PANGO_SCALE,
1540 logical_rect.width / PANGO_SCALE,
1541 overall_rect.height / PANGO_SCALE);
1543 if (info->free_gc_func)
1544 info->free_gc_func (context, bg_gc);
1547 pango_x_render (display, drawable, fg_gc, run->item->analysis.font, run->glyphs,
1548 x + x_off / PANGO_SCALE, y);
1552 case PANGO_UNDERLINE_NONE:
1554 case PANGO_UNDERLINE_DOUBLE:
1555 XDrawLine (display, drawable, fg_gc,
1556 x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + 4,
1557 x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + 4);
1559 case PANGO_UNDERLINE_SINGLE:
1560 XDrawLine (display, drawable, fg_gc,
1561 x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + 2,
1562 x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + 2);
1564 case PANGO_UNDERLINE_ERROR:
1568 int end_x = x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE;
1570 for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
1575 XDrawLine (display, drawable, gc,
1576 point_x, y + 2, MIN (point_x + 1, end_x), y + 2);
1578 XDrawLine (display, drawable, gc,
1579 point_x, y + 3, MIN (point_x + 1, end_x), y + 3);
1581 counter = (counter + 1) % 2;
1585 case PANGO_UNDERLINE_LOW:
1586 XDrawLine (display, drawable, fg_gc,
1587 x + (x_off + ink_rect.x) / PANGO_SCALE - 1, y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 2,
1588 x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE, y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 2);
1592 if (fg_set && info->get_gc_func && info->free_gc_func)
1593 info->free_gc_func (context, fg_gc);
1595 x_off += logical_rect.width;
1600 * pango_x_render_layout:
1601 * @display: the X display.
1602 * @drawable: the drawable on which to draw.
1603 * @gc: GC to use for uncolored drawing.
1604 * @layout: a #PangoLayout.
1605 * @x: the x position of the left of the layout (in pixels).
1606 * @y: the y position of the top of the layout (in pixels).
1608 * Renders a #PangoLayout onto an X drawable.
1611 pango_x_render_layout (Display *display,
1614 PangoLayout *layout,
1618 PangoLayoutIter *iter;
1620 g_return_if_fail (display != NULL);
1621 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1623 iter = pango_layout_get_iter (layout);
1627 PangoRectangle logical_rect;
1628 PangoLayoutLine *line;
1631 line = pango_layout_iter_get_line_readonly (iter);
1633 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1634 baseline = pango_layout_iter_get_baseline (iter);
1636 pango_x_render_layout_line (display, drawable, gc,
1638 x + PANGO_PIXELS (logical_rect.x),
1639 y + PANGO_PIXELS (baseline));
1641 while (pango_layout_iter_next_line (iter));
1643 pango_layout_iter_free (iter);
1646 /* This utility function is duplicated here and in pango-layout.c; should it be
1647 * public? Trouble is - what is the appropriate set of properties?
1650 pango_x_get_item_properties (PangoItem *item,
1651 PangoUnderline *uline,
1652 PangoAttrColor *fg_color,
1654 PangoAttrColor *bg_color,
1657 GSList *tmp_list = item->analysis.extra_attrs;
1667 PangoAttribute *attr = tmp_list->data;
1669 switch ((int) attr->klass->type)
1671 case PANGO_ATTR_UNDERLINE:
1673 *uline = ((PangoAttrInt *)attr)->value;
1676 case PANGO_ATTR_FOREGROUND:
1678 *fg_color = *((PangoAttrColor *)attr);
1684 case PANGO_ATTR_BACKGROUND:
1686 *bg_color = *((PangoAttrColor *)attr);
1695 tmp_list = tmp_list->next;
1700 * pango_x_apply_ligatures:
1707 * Previously did subfont-specific ligation. Now a no-op.
1709 * Return value: %FALSE, always.
1712 pango_x_apply_ligatures (PangoFont *font G_GNUC_UNUSED,
1713 PangoXSubfont subfont_id G_GNUC_UNUSED,
1714 gunichar **glyphs G_GNUC_UNUSED,
1715 int *n_glyphs G_GNUC_UNUSED,
1716 int **clusters G_GNUC_UNUSED)
1722 * pango_x_find_first_subfont:
1723 * @font: A #PangoFont.
1724 * @rfont: A pointer to a #PangoXSubfont.
1725 * @charsets: An array of charsets.
1726 * @n_charsets: The number of charsets in @charsets.
1728 * Looks for subfonts with the @charset charset,
1729 * in @font, and puts the first one in *@rfont.
1731 * Return value: %TRUE if *@rfont now contains a font.
1734 pango_x_find_first_subfont (PangoFont *font,
1737 PangoXSubfont *rfont)
1740 gboolean result = FALSE;
1741 PangoXSubfont *subfonts;
1742 int *subfont_charsets;
1744 g_return_val_if_fail (font, 0);
1745 g_return_val_if_fail (charsets, 0);
1746 g_return_val_if_fail (rfont, 0);
1748 n_subfonts = pango_x_list_subfonts (font, charsets, n_charsets,
1749 &subfonts, &subfont_charsets);
1753 *rfont = subfonts[0];
1758 g_free (subfont_charsets);
1763 * pango_x_fallback_shape:
1764 * @font: A #PangoFont.
1765 * @glyphs: A pointer to a #PangoGlyphString.
1766 * @text: UTF-8 string.
1767 * @n_chars: Number of UTF-8 seqs in @text.
1769 * This is a simple fallback shaper, that can be used
1770 * if no subfont that supports a given script is found.
1771 * For every character in @text, it puts the unknown glyph.
1774 pango_x_fallback_shape (PangoFont *font,
1775 PangoGlyphString *glyphs,
1779 PangoGlyph unknown_glyph = pango_x_get_unknown_glyph (font);
1780 PangoRectangle logical_rect;
1784 g_return_if_fail (font);
1785 g_return_if_fail (glyphs);
1786 g_return_if_fail (text);
1787 g_return_if_fail (n_chars >= 0);
1789 pango_font_get_glyph_extents (font, unknown_glyph, NULL, &logical_rect);
1790 pango_glyph_string_set_size (glyphs, n_chars);
1792 for (i = 0; i < n_chars; i++)
1794 glyphs->glyphs[i].glyph = unknown_glyph;
1796 glyphs->glyphs[i].geometry.x_offset = 0;
1797 glyphs->glyphs[i].geometry.y_offset = 0;
1798 glyphs->glyphs[i].geometry.width = logical_rect.width;
1800 glyphs->log_clusters[i] = p - text;
1802 p = g_utf8_next_char (p);
1807 * pango_x_font_get_unknown_glyph:
1808 * @font: a #PangoFont.
1809 * @wc: the Unicode character for which a glyph is needed.
1811 * Returns the index of a glyph suitable for drawing @wc as an
1812 * unknown character.
1814 * Use PANGO_GET_UNKNOWN_GLYPH() instead.
1816 * Return value: a glyph index into @font.
1819 pango_x_font_get_unknown_glyph (PangoFont *font G_GNUC_UNUSED,
1822 return PANGO_GET_UNKNOWN_GLYPH (wc);