1 | /* Pango |
2 | * pango-fontset.c: |
3 | * |
4 | * Copyright (C) 2001 Red Hat Software |
5 | * |
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. |
10 | * |
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. |
15 | * |
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. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | |
24 | /* |
25 | * PangoFontset |
26 | */ |
27 | |
28 | #include "pango-types.h" |
29 | #include "pango-font-private.h" |
30 | #include "pango-fontset.h" |
31 | #include "pango-impl-utils.h" |
32 | |
33 | static PangoFontMetrics *pango_fontset_real_get_metrics (PangoFontset *fontset); |
34 | |
35 | |
36 | G_DEFINE_ABSTRACT_TYPE (PangoFontset, pango_fontset, G_TYPE_OBJECT); |
37 | |
38 | static void |
39 | pango_fontset_init (PangoFontset *self) |
40 | { |
41 | } |
42 | |
43 | static void |
44 | pango_fontset_class_init (PangoFontsetClass *class) |
45 | { |
46 | class->get_metrics = pango_fontset_real_get_metrics; |
47 | } |
48 | |
49 | |
50 | /** |
51 | * pango_fontset_get_font: |
52 | * @fontset: a `PangoFontset` |
53 | * @wc: a Unicode character |
54 | * |
55 | * Returns the font in the fontset that contains the best |
56 | * glyph for a Unicode character. |
57 | * |
58 | * Return value: (transfer full): a `PangoFont` |
59 | */ |
60 | PangoFont * |
61 | pango_fontset_get_font (PangoFontset *fontset, |
62 | guint wc) |
63 | { |
64 | |
65 | g_return_val_if_fail (PANGO_IS_FONTSET (fontset), NULL); |
66 | |
67 | return PANGO_FONTSET_GET_CLASS (fontset)->get_font (fontset, wc); |
68 | } |
69 | |
70 | /** |
71 | * pango_fontset_get_metrics: |
72 | * @fontset: a `PangoFontset` |
73 | * |
74 | * Get overall metric information for the fonts in the fontset. |
75 | * |
76 | * Return value: a `PangoFontMetrics` object |
77 | */ |
78 | PangoFontMetrics * |
79 | pango_fontset_get_metrics (PangoFontset *fontset) |
80 | { |
81 | g_return_val_if_fail (PANGO_IS_FONTSET (fontset), NULL); |
82 | |
83 | return PANGO_FONTSET_GET_CLASS (fontset)->get_metrics (fontset); |
84 | } |
85 | |
86 | /** |
87 | * pango_fontset_foreach: |
88 | * @fontset: a `PangoFontset` |
89 | * @func: (closure data) (scope call): Callback function |
90 | * @data: (closure): data to pass to the callback function |
91 | * |
92 | * Iterates through all the fonts in a fontset, calling @func for |
93 | * each one. |
94 | * |
95 | * If @func returns %TRUE, that stops the iteration. |
96 | * |
97 | * Since: 1.4 |
98 | */ |
99 | void |
100 | pango_fontset_foreach (PangoFontset *fontset, |
101 | PangoFontsetForeachFunc func, |
102 | gpointer data) |
103 | { |
104 | g_return_if_fail (PANGO_IS_FONTSET (fontset)); |
105 | g_return_if_fail (func != NULL); |
106 | |
107 | PANGO_FONTSET_GET_CLASS (fontset)->foreach (fontset, func, data); |
108 | } |
109 | |
110 | static gboolean |
111 | get_first_metrics_foreach (PangoFontset *fontset, |
112 | PangoFont *font, |
113 | gpointer data) |
114 | { |
115 | PangoFontMetrics *fontset_metrics = data; |
116 | PangoLanguage *language = PANGO_FONTSET_GET_CLASS (fontset)->get_language (fontset); |
117 | PangoFontMetrics *font_metrics = pango_font_get_metrics (font, language); |
118 | guint save_ref_count; |
119 | |
120 | /* Initialize the fontset metrics to metrics of the first font in the |
121 | * fontset; saving the refcount and restoring it is a bit of hack but avoids |
122 | * having to update this code for each metrics addition. |
123 | */ |
124 | save_ref_count = fontset_metrics->ref_count; |
125 | *fontset_metrics = *font_metrics; |
126 | fontset_metrics->ref_count = save_ref_count; |
127 | |
128 | pango_font_metrics_unref (metrics: font_metrics); |
129 | |
130 | return TRUE; /* Stops iteration */ |
131 | } |
132 | |
133 | static PangoFontMetrics * |
134 | pango_fontset_real_get_metrics (PangoFontset *fontset) |
135 | { |
136 | PangoFontMetrics *metrics, *raw_metrics; |
137 | const char *sample_str; |
138 | const char *p; |
139 | int count; |
140 | GHashTable *fonts_seen; |
141 | PangoFont *font; |
142 | PangoLanguage *language; |
143 | |
144 | language = PANGO_FONTSET_GET_CLASS (fontset)->get_language (fontset); |
145 | sample_str = pango_language_get_sample_string (language); |
146 | |
147 | count = 0; |
148 | metrics = pango_font_metrics_new (); |
149 | fonts_seen = g_hash_table_new_full (NULL, NULL, key_destroy_func: g_object_unref, NULL); |
150 | |
151 | /* Initialize the metrics from the first font in the fontset */ |
152 | pango_fontset_foreach (fontset, func: get_first_metrics_foreach, data: metrics); |
153 | |
154 | p = sample_str; |
155 | while (*p) |
156 | { |
157 | gunichar wc = g_utf8_get_char (p); |
158 | font = pango_fontset_get_font (fontset, wc); |
159 | if (font) |
160 | { |
161 | if (g_hash_table_lookup (hash_table: fonts_seen, key: font) == NULL) |
162 | { |
163 | raw_metrics = pango_font_get_metrics (font, language); |
164 | g_hash_table_insert (hash_table: fonts_seen, key: font, value: font); |
165 | |
166 | if (count == 0) |
167 | { |
168 | metrics->ascent = raw_metrics->ascent; |
169 | metrics->descent = raw_metrics->descent; |
170 | metrics->approximate_char_width = raw_metrics->approximate_char_width; |
171 | metrics->approximate_digit_width = raw_metrics->approximate_digit_width; |
172 | } |
173 | else |
174 | { |
175 | metrics->ascent = MAX (metrics->ascent, raw_metrics->ascent); |
176 | metrics->descent = MAX (metrics->descent, raw_metrics->descent); |
177 | metrics->approximate_char_width += raw_metrics->approximate_char_width; |
178 | metrics->approximate_digit_width += raw_metrics->approximate_digit_width; |
179 | } |
180 | count++; |
181 | pango_font_metrics_unref (metrics: raw_metrics); |
182 | } |
183 | else |
184 | g_object_unref (object: font); |
185 | } |
186 | |
187 | p = g_utf8_next_char (p); |
188 | } |
189 | |
190 | g_hash_table_destroy (hash_table: fonts_seen); |
191 | |
192 | if (count) |
193 | { |
194 | metrics->approximate_char_width /= count; |
195 | metrics->approximate_digit_width /= count; |
196 | } |
197 | |
198 | return metrics; |
199 | } |
200 | |