File: | font-viewer/sushi-font-widget.c |
Warning: | line 507, column 5 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (C) 2011 Red Hat, Inc. | |||
3 | * | |||
4 | * This program is free software; you can redistribute it and/or | |||
5 | * modify it under the terms of the GNU General Public License as | |||
6 | * published by the Free Software Foundation; either version 2 of the | |||
7 | * License, or (at your option) any later version. | |||
8 | * | |||
9 | * This program is distributed in the hope that it will be useful, but | |||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
12 | * General Public License for more details. | |||
13 | * | |||
14 | * You should have received a copy of the GNU General Public License | |||
15 | * along with this program; if not, write to the Free Software | |||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |||
17 | * 02111-1307, USA. | |||
18 | * | |||
19 | * The Sushi project hereby grant permission for non-gpl compatible GStreamer | |||
20 | * plugins to be used and distributed together with GStreamer and Sushi. This | |||
21 | * permission is above and beyond the permissions granted by the GPL license | |||
22 | * Sushi is covered by. | |||
23 | * | |||
24 | * Authors: Cosimo Cecchi <cosimoc@redhat.com> | |||
25 | * | |||
26 | */ | |||
27 | ||||
28 | #include "sushi-font-widget.h" | |||
29 | #include "sushi-font-loader.h" | |||
30 | ||||
31 | #include <math.h> | |||
32 | ||||
33 | enum { | |||
34 | PROP_URI = 1, | |||
35 | PROP_FACE_INDEX, | |||
36 | NUM_PROPERTIES | |||
37 | }; | |||
38 | ||||
39 | enum { | |||
40 | LOADED, | |||
41 | ERROR, | |||
42 | NUM_SIGNALS | |||
43 | }; | |||
44 | ||||
45 | struct _SushiFontWidgetPrivate { | |||
46 | gchar *uri; | |||
47 | gint face_index; | |||
48 | ||||
49 | FT_Library library; | |||
50 | FT_Face face; | |||
51 | gchar *face_contents; | |||
52 | ||||
53 | const gchar *lowercase_text; | |||
54 | const gchar *uppercase_text; | |||
55 | const gchar *punctuation_text; | |||
56 | ||||
57 | gchar *sample_string; | |||
58 | ||||
59 | gchar *font_name; | |||
60 | }; | |||
61 | ||||
62 | static GParamSpec *properties[NUM_PROPERTIES] = { NULL((void*)0), }; | |||
63 | static guint signals[NUM_SIGNALS] = { 0, }; | |||
64 | ||||
65 | G_DEFINE_TYPE_WITH_PRIVATE (SushiFontWidget, sushi_font_widget, CTK_TYPE_DRAWING_AREA)static void sushi_font_widget_init (SushiFontWidget *self); static void sushi_font_widget_class_init (SushiFontWidgetClass *klass ); static GType sushi_font_widget_get_type_once (void); static gpointer sushi_font_widget_parent_class = ((void*)0); static gint SushiFontWidget_private_offset; static void sushi_font_widget_class_intern_init (gpointer klass) { sushi_font_widget_parent_class = g_type_class_peek_parent (klass); if (SushiFontWidget_private_offset != 0) g_type_class_adjust_private_offset (klass, &SushiFontWidget_private_offset); sushi_font_widget_class_init ((SushiFontWidgetClass*) klass); } __attribute__ ((__unused__ )) static inline gpointer sushi_font_widget_get_instance_private (SushiFontWidget *self) { return (((gpointer) ((guint8*) (self ) + (glong) (SushiFontWidget_private_offset)))); } GType sushi_font_widget_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = sushi_font_widget_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType sushi_font_widget_get_type_once ( void) { GType g_define_type_id = g_type_register_static_simple ((ctk_drawing_area_get_type ()), g_intern_static_string ("SushiFontWidget" ), sizeof (SushiFontWidgetClass), (GClassInitFunc)(void (*)(void )) sushi_font_widget_class_intern_init, sizeof (SushiFontWidget ), (GInstanceInitFunc)(void (*)(void)) sushi_font_widget_init , (GTypeFlags) 0); { {{ SushiFontWidget_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (SushiFontWidgetPrivate)); };} } return g_define_type_id; }; | |||
66 | ||||
67 | #define SURFACE_SIZE4 4 | |||
68 | #define SECTION_SPACING16 16 | |||
69 | #define LINE_SPACING2 2 | |||
70 | ||||
71 | static const gchar lowercase_text_stock[] = "abcdefghijklmnopqrstuvwxyz"; | |||
72 | static const gchar uppercase_text_stock[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |||
73 | static const gchar punctuation_text_stock[] = "0123456789.:,;(*!?')"; | |||
74 | ||||
75 | /* adapted from gnome-utils:font-viewer/font-view.c | |||
76 | * | |||
77 | * Copyright (C) 2002-2003 James Henstridge <james@daa.com.au> | |||
78 | * Copyright (C) 2010 Cosimo Cecchi <cosimoc@gnome.org> | |||
79 | * | |||
80 | * License: GPLv2+ | |||
81 | */ | |||
82 | static void | |||
83 | draw_string (SushiFontWidget *self, | |||
84 | cairo_t *cr, | |||
85 | CtkBorder padding, | |||
86 | const gchar *text, | |||
87 | gint *pos_y) | |||
88 | { | |||
89 | cairo_font_extents_t font_extents; | |||
90 | cairo_text_extents_t extents; | |||
91 | CtkTextDirection text_dir; | |||
92 | gint pos_x; | |||
93 | ||||
94 | text_dir = ctk_widget_get_direction (CTK_WIDGET (self)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), ((ctk_widget_get_type ()))))))); | |||
95 | ||||
96 | cairo_font_extents (cr, &font_extents); | |||
97 | cairo_text_extents (cr, text, &extents); | |||
98 | ||||
99 | if (pos_y != NULL((void*)0)) | |||
100 | *pos_y += font_extents.ascent + font_extents.descent + | |||
101 | extents.y_advance + LINE_SPACING2 / 2; | |||
102 | if (text_dir == CTK_TEXT_DIR_LTR) | |||
103 | pos_x = padding.left; | |||
104 | else { | |||
105 | pos_x = ctk_widget_get_allocated_width (CTK_WIDGET (self)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), ((ctk_widget_get_type ()))))))) - | |||
106 | extents.x_advance - padding.right; | |||
107 | } | |||
108 | ||||
109 | cairo_move_to (cr, pos_x, *pos_y); | |||
110 | cairo_show_text (cr, text); | |||
111 | ||||
112 | *pos_y += LINE_SPACING2 / 2; | |||
113 | } | |||
114 | ||||
115 | static gboolean | |||
116 | check_font_contain_text (FT_Face face, | |||
117 | const gchar *text) | |||
118 | { | |||
119 | gunichar *string; | |||
120 | glong len, idx, map; | |||
121 | FT_CharMap charmap; | |||
122 | gboolean retval = FALSE(0); | |||
123 | ||||
124 | string = g_utf8_to_ucs4_fast (text, -1, &len); | |||
125 | ||||
126 | for (map = 0; map < face->num_charmaps; map++) { | |||
127 | charmap = face->charmaps[map]; | |||
128 | FT_Set_Charmap (face, charmap); | |||
129 | ||||
130 | retval = TRUE(!(0)); | |||
131 | ||||
132 | for (idx = 0; idx < len; idx++) { | |||
133 | gunichar c = string[idx]; | |||
134 | ||||
135 | if (!FT_Get_Char_Index (face, c)) { | |||
136 | retval = FALSE(0); | |||
137 | break; | |||
138 | } | |||
139 | } | |||
140 | ||||
141 | if (retval) | |||
142 | break; | |||
143 | } | |||
144 | ||||
145 | g_free (string); | |||
146 | ||||
147 | return retval; | |||
148 | } | |||
149 | ||||
150 | static gchar * | |||
151 | build_charlist_for_face (FT_Face face, | |||
152 | gint *length) | |||
153 | { | |||
154 | GString *string; | |||
155 | gulong c; | |||
156 | guint glyph; | |||
157 | gint total_chars = 0; | |||
158 | ||||
159 | string = g_string_new (NULL((void*)0)); | |||
160 | ||||
161 | c = FT_Get_First_Char (face, &glyph); | |||
162 | ||||
163 | while (glyph != 0) { | |||
164 | g_string_append_unichar (string, (gunichar) c); | |||
165 | c = FT_Get_Next_Char (face, c, &glyph); | |||
166 | total_chars++; | |||
167 | } | |||
168 | ||||
169 | if (length) | |||
170 | *length = total_chars; | |||
171 | ||||
172 | return g_string_free (string, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((string ), ((0))) : g_string_free_and_steal (string)) : (g_string_free ) ((string), ((0)))); | |||
173 | } | |||
174 | ||||
175 | static gchar * | |||
176 | random_string_from_available_chars (FT_Face face, | |||
177 | gint n_chars) | |||
178 | { | |||
179 | gchar *chars; | |||
180 | gint idx, rand, total_chars; | |||
181 | GString *retval; | |||
182 | gchar *ptr, *end; | |||
183 | ||||
184 | idx = 0; | |||
185 | chars = build_charlist_for_face (face, &total_chars); | |||
186 | ||||
187 | if (total_chars == 0) | |||
188 | return NULL((void*)0); | |||
189 | ||||
190 | retval = g_string_new (NULL((void*)0)); | |||
191 | ||||
192 | while (idx < n_chars) { | |||
193 | rand = g_random_int_range (0, total_chars); | |||
194 | ||||
195 | ptr = g_utf8_offset_to_pointer (chars, rand); | |||
196 | end = g_utf8_find_next_char (ptr, NULL((void*)0)); | |||
197 | ||||
198 | g_string_append_len (retval, ptr, end - ptr)g_string_append_len_inline (retval, ptr, end - ptr); | |||
199 | idx++; | |||
200 | } | |||
201 | ||||
202 | return g_string_free (retval, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((retval ), ((0))) : g_string_free_and_steal (retval)) : (g_string_free ) ((retval), ((0)))); | |||
203 | } | |||
204 | ||||
205 | static gboolean | |||
206 | set_pango_sample_string (SushiFontWidget *self) | |||
207 | { | |||
208 | const gchar *sample_string; | |||
209 | gboolean retval = FALSE(0); | |||
210 | ||||
211 | sample_string = pango_language_get_sample_string (pango_language_from_string (NULL((void*)0))); | |||
212 | if (check_font_contain_text (self->priv->face, sample_string)) | |||
213 | retval = TRUE(!(0)); | |||
214 | ||||
215 | if (!retval) { | |||
216 | sample_string = pango_language_get_sample_string (pango_language_from_string ("C")); | |||
217 | if (check_font_contain_text (self->priv->face, sample_string)) | |||
218 | retval = TRUE(!(0)); | |||
219 | } | |||
220 | ||||
221 | if (retval) { | |||
222 | g_free (self->priv->sample_string); | |||
223 | self->priv->sample_string = g_strdup (sample_string)g_strdup_inline (sample_string); | |||
224 | } | |||
225 | ||||
226 | return retval; | |||
227 | } | |||
228 | ||||
229 | static void | |||
230 | build_strings_for_face (SushiFontWidget *self) | |||
231 | { | |||
232 | /* if we don't have lowercase/uppercase/punctuation text in the face, | |||
233 | * we omit it directly, and render a random text below. | |||
234 | */ | |||
235 | if (check_font_contain_text (self->priv->face, lowercase_text_stock)) | |||
236 | self->priv->lowercase_text = lowercase_text_stock; | |||
237 | else | |||
238 | self->priv->lowercase_text = NULL((void*)0); | |||
239 | ||||
240 | if (check_font_contain_text (self->priv->face, uppercase_text_stock)) | |||
241 | self->priv->uppercase_text = uppercase_text_stock; | |||
242 | else | |||
243 | self->priv->uppercase_text = NULL((void*)0); | |||
244 | ||||
245 | if (check_font_contain_text (self->priv->face, punctuation_text_stock)) | |||
246 | self->priv->punctuation_text = punctuation_text_stock; | |||
247 | else | |||
248 | self->priv->punctuation_text = NULL((void*)0); | |||
249 | ||||
250 | if (!set_pango_sample_string (self)) | |||
251 | self->priv->sample_string = random_string_from_available_chars (self->priv->face, 36); | |||
252 | ||||
253 | g_free (self->priv->font_name); | |||
254 | self->priv->font_name = NULL((void*)0); | |||
255 | ||||
256 | if (self->priv->face->family_name != NULL((void*)0)) { | |||
257 | gchar *font_name = | |||
258 | g_strconcat (self->priv->face->family_name, " ", | |||
259 | self->priv->face->style_name, NULL((void*)0)); | |||
260 | ||||
261 | if (check_font_contain_text (self->priv->face, font_name)) | |||
262 | self->priv->font_name = font_name; | |||
263 | else | |||
264 | g_free (font_name); | |||
265 | } | |||
266 | } | |||
267 | ||||
268 | static gint * | |||
269 | build_sizes_table (FT_Face face, | |||
270 | gint *n_sizes, | |||
271 | gint *alpha_size, | |||
272 | gint *title_size) | |||
273 | { | |||
274 | gint *sizes = NULL((void*)0); | |||
275 | gint i; | |||
276 | ||||
277 | /* work out what sizes to render */ | |||
278 | if (FT_IS_SCALABLE (face)( !!( (face)->face_flags & ( 1L << 0 ) ) )) { | |||
279 | *n_sizes = 14; | |||
280 | sizes = g_new (gint, *n_sizes)((gint *) g_malloc_n ((*n_sizes), sizeof (gint))); | |||
281 | sizes[0] = 8; | |||
282 | sizes[1] = 10; | |||
283 | sizes[2] = 12; | |||
284 | sizes[3] = 18; | |||
285 | sizes[4] = 24; | |||
286 | sizes[5] = 36; | |||
287 | sizes[6] = 48; | |||
288 | sizes[7] = 72; | |||
289 | sizes[8] = 96; | |||
290 | sizes[9] = 120; | |||
291 | sizes[10] = 144; | |||
292 | sizes[11] = 168; | |||
293 | sizes[12] = 192; | |||
294 | sizes[13] = 216; | |||
295 | ||||
296 | *alpha_size = 24; | |||
297 | *title_size = 48; | |||
298 | } else { | |||
299 | gint alpha_diff = G_MAXINT2147483647; | |||
300 | gint title_diff = G_MAXINT2147483647; | |||
301 | ||||
302 | /* use fixed sizes */ | |||
303 | *n_sizes = face->num_fixed_sizes; | |||
304 | sizes = g_new (gint, *n_sizes)((gint *) g_malloc_n ((*n_sizes), sizeof (gint))); | |||
305 | *alpha_size = 0; | |||
306 | ||||
307 | for (i = 0; i < face->num_fixed_sizes; i++) { | |||
308 | sizes[i] = face->available_sizes[i].height; | |||
309 | ||||
310 | if ((gint) (abs (sizes[i] - 24)) < alpha_diff) { | |||
311 | alpha_diff = (gint) abs (sizes[i] - 24); | |||
312 | *alpha_size = sizes[i]; | |||
313 | } | |||
314 | if ((gint) (abs (sizes[i] - 24)) < title_diff) { | |||
315 | title_diff = (gint) abs (sizes[i] - 24); | |||
316 | *title_size = sizes[i]; | |||
317 | } | |||
318 | } | |||
319 | } | |||
320 | ||||
321 | return sizes; | |||
322 | } | |||
323 | ||||
324 | static void | |||
325 | sushi_font_widget_size_request (CtkWidget *drawing_area, | |||
326 | gint *width, | |||
327 | gint *height, | |||
328 | gint *min_height) | |||
329 | { | |||
330 | SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((drawing_area)), ((sushi_font_widget_get_type ())))))); | |||
331 | SushiFontWidgetPrivate *priv = self->priv; | |||
332 | gint i, pixmap_width, pixmap_height; | |||
333 | cairo_text_extents_t extents; | |||
334 | cairo_font_extents_t font_extents; | |||
335 | cairo_font_face_t *font; | |||
336 | gint *sizes = NULL((void*)0), n_sizes, alpha_size, title_size; | |||
337 | cairo_t *cr; | |||
338 | cairo_surface_t *surface; | |||
339 | FT_Face face = priv->face; | |||
340 | CtkStyleContext *context; | |||
341 | CtkStateFlags state; | |||
342 | CtkBorder padding; | |||
343 | ||||
344 | if (face == NULL((void*)0)) { | |||
345 | if (width != NULL((void*)0)) | |||
346 | *width = 1; | |||
347 | if (height != NULL((void*)0)) | |||
348 | *height = 1; | |||
349 | if (min_height != NULL((void*)0)) | |||
350 | *min_height = 1; | |||
351 | ||||
352 | return; | |||
353 | } | |||
354 | ||||
355 | if (min_height != NULL((void*)0)) | |||
356 | *min_height = -1; | |||
357 | ||||
358 | surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, | |||
359 | SURFACE_SIZE4, SURFACE_SIZE4); | |||
360 | cr = cairo_create (surface); | |||
361 | context = ctk_widget_get_style_context (drawing_area); | |||
362 | state = ctk_style_context_get_state (context); | |||
363 | ctk_style_context_get_padding (context, state, &padding); | |||
364 | ||||
365 | sizes = build_sizes_table (face, &n_sizes, &alpha_size, &title_size); | |||
366 | ||||
367 | /* calculate size of pixmap to use */ | |||
368 | pixmap_width = padding.left + padding.right; | |||
369 | pixmap_height = padding.top + padding.bottom; | |||
370 | ||||
371 | font = cairo_ft_font_face_create_for_ft_face (face, 0); | |||
372 | cairo_set_font_face (cr, font); | |||
373 | cairo_font_face_destroy (font); | |||
374 | ||||
375 | if (self->priv->font_name != NULL((void*)0)) { | |||
376 | cairo_set_font_size (cr, title_size); | |||
377 | cairo_font_extents (cr, &font_extents); | |||
378 | cairo_text_extents (cr, self->priv->font_name, &extents); | |||
379 | pixmap_height += font_extents.ascent + font_extents.descent + | |||
380 | extents.y_advance + LINE_SPACING2; | |||
381 | pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right)(((pixmap_width) > (extents.width + padding.left + padding .right)) ? (pixmap_width) : (extents.width + padding.left + padding .right)); | |||
382 | } | |||
383 | ||||
384 | pixmap_height += SECTION_SPACING16 / 2; | |||
385 | cairo_set_font_size (cr, alpha_size); | |||
386 | cairo_font_extents (cr, &font_extents); | |||
387 | ||||
388 | if (self->priv->lowercase_text != NULL((void*)0)) { | |||
389 | cairo_text_extents (cr, self->priv->lowercase_text, &extents); | |||
390 | pixmap_height += font_extents.ascent + font_extents.descent + | |||
391 | extents.y_advance + LINE_SPACING2; | |||
392 | pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right)(((pixmap_width) > (extents.width + padding.left + padding .right)) ? (pixmap_width) : (extents.width + padding.left + padding .right)); | |||
393 | } | |||
394 | ||||
395 | if (self->priv->uppercase_text != NULL((void*)0)) { | |||
396 | cairo_text_extents (cr, self->priv->uppercase_text, &extents); | |||
397 | pixmap_height += font_extents.ascent + font_extents.descent + | |||
398 | extents.y_advance + LINE_SPACING2; | |||
399 | pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right)(((pixmap_width) > (extents.width + padding.left + padding .right)) ? (pixmap_width) : (extents.width + padding.left + padding .right)); | |||
400 | } | |||
401 | ||||
402 | if (self->priv->punctuation_text != NULL((void*)0)) { | |||
403 | cairo_text_extents (cr, self->priv->punctuation_text, &extents); | |||
404 | pixmap_height += font_extents.ascent + font_extents.descent + | |||
405 | extents.y_advance + LINE_SPACING2; | |||
406 | pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right)(((pixmap_width) > (extents.width + padding.left + padding .right)) ? (pixmap_width) : (extents.width + padding.left + padding .right)); | |||
407 | } | |||
408 | ||||
409 | if (self->priv->sample_string != NULL((void*)0)) { | |||
410 | pixmap_height += SECTION_SPACING16; | |||
411 | ||||
412 | for (i = 0; i < n_sizes; i++) { | |||
413 | cairo_set_font_size (cr, sizes[i]); | |||
414 | cairo_font_extents (cr, &font_extents); | |||
415 | cairo_text_extents (cr, self->priv->sample_string, &extents); | |||
416 | pixmap_height += font_extents.ascent + font_extents.descent + | |||
417 | extents.y_advance + LINE_SPACING2; | |||
418 | pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right)(((pixmap_width) > (extents.width + padding.left + padding .right)) ? (pixmap_width) : (extents.width + padding.left + padding .right)); | |||
419 | ||||
420 | if ((i == 7) && (min_height != NULL((void*)0))) | |||
421 | *min_height = pixmap_height; | |||
422 | } | |||
423 | } | |||
424 | ||||
425 | pixmap_height += padding.bottom + SECTION_SPACING16; | |||
426 | ||||
427 | if (min_height != NULL((void*)0) && *min_height == -1) | |||
428 | *min_height = pixmap_height; | |||
429 | ||||
430 | if (width != NULL((void*)0)) | |||
431 | *width = pixmap_width; | |||
432 | ||||
433 | if (height != NULL((void*)0)) | |||
434 | *height = pixmap_height; | |||
435 | ||||
436 | cairo_destroy (cr); | |||
437 | cairo_surface_destroy (surface); | |||
438 | g_free (sizes); | |||
439 | } | |||
440 | ||||
441 | static void | |||
442 | sushi_font_widget_get_preferred_width (CtkWidget *drawing_area, | |||
443 | gint *minimum_width, | |||
444 | gint *natural_width) | |||
445 | { | |||
446 | gint width; | |||
447 | ||||
448 | sushi_font_widget_size_request (drawing_area, &width, NULL((void*)0), NULL((void*)0)); | |||
449 | ||||
450 | *minimum_width = *natural_width = width; | |||
451 | } | |||
452 | ||||
453 | static void | |||
454 | sushi_font_widget_get_preferred_height (CtkWidget *drawing_area, | |||
455 | gint *minimum_height, | |||
456 | gint *natural_height) | |||
457 | { | |||
458 | gint height, min_height; | |||
459 | ||||
460 | sushi_font_widget_size_request (drawing_area, NULL((void*)0), &height, &min_height); | |||
461 | ||||
462 | *minimum_height = min_height; | |||
463 | *natural_height = height; | |||
464 | } | |||
465 | ||||
466 | static gboolean | |||
467 | sushi_font_widget_draw (CtkWidget *drawing_area, | |||
468 | cairo_t *cr) | |||
469 | { | |||
470 | SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((drawing_area)), ((sushi_font_widget_get_type ())))))); | |||
471 | SushiFontWidgetPrivate *priv = self->priv; | |||
472 | gint *sizes = NULL((void*)0), n_sizes, alpha_size, title_size, pos_y = 0, i; | |||
| ||||
473 | cairo_font_face_t *font; | |||
474 | FT_Face face = priv->face; | |||
475 | CtkStyleContext *context; | |||
476 | CdkRGBA color; | |||
477 | CtkBorder padding; | |||
478 | CtkStateFlags state; | |||
479 | gint allocated_width, allocated_height; | |||
480 | ||||
481 | if (face == NULL((void*)0)) | |||
482 | goto end; | |||
483 | ||||
484 | context = ctk_widget_get_style_context (drawing_area); | |||
485 | state = ctk_style_context_get_state (context); | |||
486 | ||||
487 | allocated_width = ctk_widget_get_allocated_width (drawing_area); | |||
488 | allocated_height = ctk_widget_get_allocated_height (drawing_area); | |||
489 | ||||
490 | ctk_render_background (context, cr, | |||
491 | 0, 0, allocated_width, allocated_height); | |||
492 | ||||
493 | ctk_style_context_get_color (context, state, &color); | |||
494 | ctk_style_context_get_padding (context, state, &padding); | |||
495 | ||||
496 | cdk_cairo_set_source_rgba (cr, &color); | |||
497 | ||||
498 | sizes = build_sizes_table (face, &n_sizes, &alpha_size, &title_size); | |||
499 | ||||
500 | font = cairo_ft_font_face_create_for_ft_face (face, 0); | |||
501 | cairo_set_font_face (cr, font); | |||
502 | cairo_font_face_destroy (font); | |||
503 | ||||
504 | /* draw text */ | |||
505 | ||||
506 | if (self->priv->font_name != NULL((void*)0)) { | |||
507 | cairo_set_font_size (cr, title_size); | |||
| ||||
508 | draw_string (self, cr, padding, self->priv->font_name, &pos_y); | |||
509 | } | |||
510 | ||||
511 | if (pos_y > allocated_height) | |||
512 | goto end; | |||
513 | ||||
514 | pos_y += SECTION_SPACING16 / 2; | |||
515 | cairo_set_font_size (cr, alpha_size); | |||
516 | ||||
517 | if (self->priv->lowercase_text != NULL((void*)0)) | |||
518 | draw_string (self, cr, padding, self->priv->lowercase_text, &pos_y); | |||
519 | if (pos_y > allocated_height) | |||
520 | goto end; | |||
521 | ||||
522 | if (self->priv->uppercase_text != NULL((void*)0)) | |||
523 | draw_string (self, cr, padding, self->priv->uppercase_text, &pos_y); | |||
524 | if (pos_y > allocated_height) | |||
525 | goto end; | |||
526 | ||||
527 | if (self->priv->punctuation_text != NULL((void*)0)) | |||
528 | draw_string (self, cr, padding, self->priv->punctuation_text, &pos_y); | |||
529 | if (pos_y > allocated_height) | |||
530 | goto end; | |||
531 | ||||
532 | pos_y += SECTION_SPACING16; | |||
533 | ||||
534 | for (i = 0; i < n_sizes; i++) { | |||
535 | cairo_set_font_size (cr, sizes[i]); | |||
536 | draw_string (self, cr, padding, self->priv->sample_string, &pos_y); | |||
537 | if (pos_y > allocated_height) | |||
538 | break; | |||
539 | } | |||
540 | ||||
541 | end: | |||
542 | g_free (sizes); | |||
543 | ||||
544 | return FALSE(0); | |||
545 | } | |||
546 | ||||
547 | static void | |||
548 | font_face_async_ready_cb (GObject *object, | |||
549 | GAsyncResult *result, | |||
550 | gpointer user_data) | |||
551 | { | |||
552 | SushiFontWidget *self = user_data; | |||
553 | GError *error = NULL((void*)0); | |||
554 | ||||
555 | self->priv->face = | |||
556 | sushi_new_ft_face_from_uri_finish (result, | |||
557 | &self->priv->face_contents, | |||
558 | &error); | |||
559 | ||||
560 | if (error != NULL((void*)0)) { | |||
561 | g_signal_emit (self, signals[ERROR], 0, error->message); | |||
562 | g_print ("Can't load the font face: %s\n", error->message); | |||
563 | g_error_free (error); | |||
564 | ||||
565 | return; | |||
566 | } | |||
567 | ||||
568 | build_strings_for_face (self); | |||
569 | ||||
570 | ctk_widget_queue_resize (CTK_WIDGET (self)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), ((ctk_widget_get_type ()))))))); | |||
571 | g_signal_emit (self, signals[LOADED], 0); | |||
572 | } | |||
573 | ||||
574 | void | |||
575 | sushi_font_widget_load (SushiFontWidget *self) | |||
576 | { | |||
577 | sushi_new_ft_face_from_uri_async (self->priv->library, | |||
578 | self->priv->uri, | |||
579 | self->priv->face_index, | |||
580 | font_face_async_ready_cb, | |||
581 | self); | |||
582 | } | |||
583 | ||||
584 | static void | |||
585 | sushi_font_widget_init (SushiFontWidget *self) | |||
586 | { | |||
587 | FT_Error err; | |||
588 | ||||
589 | self->priv = sushi_font_widget_get_instance_private (self); | |||
590 | ||||
591 | self->priv->face = NULL((void*)0); | |||
592 | err = FT_Init_FreeType (&self->priv->library); | |||
593 | ||||
594 | if (err != FT_Err_Ok) | |||
595 | g_error ("Unable to initialize FreeType"); | |||
596 | ||||
597 | ctk_style_context_add_class (ctk_widget_get_style_context (CTK_WIDGET (self)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), ((ctk_widget_get_type ()))))))), | |||
598 | CTK_STYLE_CLASS_VIEW"view"); | |||
599 | } | |||
600 | ||||
601 | static void | |||
602 | sushi_font_widget_get_property (GObject *object, | |||
603 | guint prop_id, | |||
604 | GValue *value, | |||
605 | GParamSpec *pspec) | |||
606 | { | |||
607 | SushiFontWidget *self = SUSHI_FONT_WIDGET (object)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((sushi_font_widget_get_type ())))))); | |||
608 | ||||
609 | switch (prop_id) { | |||
610 | case PROP_URI: | |||
611 | g_value_set_string (value, self->priv->uri); | |||
612 | break; | |||
613 | case PROP_FACE_INDEX: | |||
614 | g_value_set_int (value, self->priv->face_index); | |||
615 | break; | |||
616 | default: | |||
617 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "sushi-font-widget.c", 617, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); | |||
618 | break; | |||
619 | } | |||
620 | } | |||
621 | ||||
622 | static void | |||
623 | sushi_font_widget_set_property (GObject *object, | |||
624 | guint prop_id, | |||
625 | const GValue *value, | |||
626 | GParamSpec *pspec) | |||
627 | { | |||
628 | SushiFontWidget *self = SUSHI_FONT_WIDGET (object)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((sushi_font_widget_get_type ())))))); | |||
629 | ||||
630 | switch (prop_id) { | |||
631 | case PROP_URI: | |||
632 | self->priv->uri = g_value_dup_string (value); | |||
633 | break; | |||
634 | case PROP_FACE_INDEX: | |||
635 | self->priv->face_index = g_value_get_int (value); | |||
636 | break; | |||
637 | default: | |||
638 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "sushi-font-widget.c", 638, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); | |||
639 | break; | |||
640 | } | |||
641 | } | |||
642 | ||||
643 | static void | |||
644 | sushi_font_widget_finalize (GObject *object) | |||
645 | { | |||
646 | SushiFontWidget *self = SUSHI_FONT_WIDGET (object)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((sushi_font_widget_get_type ())))))); | |||
647 | ||||
648 | g_free (self->priv->uri); | |||
649 | ||||
650 | if (self->priv->face != NULL((void*)0)) { | |||
651 | FT_Done_Face (self->priv->face); | |||
652 | self->priv->face = NULL((void*)0); | |||
653 | } | |||
654 | ||||
655 | g_free (self->priv->font_name); | |||
656 | g_free (self->priv->sample_string); | |||
657 | g_free (self->priv->face_contents); | |||
658 | ||||
659 | if (self->priv->library != NULL((void*)0)) { | |||
660 | FT_Done_FreeType (self->priv->library); | |||
661 | self->priv->library = NULL((void*)0); | |||
662 | } | |||
663 | ||||
664 | G_OBJECT_CLASS (sushi_font_widget_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((sushi_font_widget_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); | |||
665 | } | |||
666 | ||||
667 | static void | |||
668 | sushi_font_widget_constructed (GObject *object) | |||
669 | { | |||
670 | SushiFontWidget *self = SUSHI_FONT_WIDGET (object)((((SushiFontWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((sushi_font_widget_get_type ())))))); | |||
671 | ||||
672 | sushi_font_widget_load (self); | |||
673 | ||||
674 | G_OBJECT_CLASS (sushi_font_widget_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((sushi_font_widget_parent_class)), (((GType) ((20) << (2))))))))->constructed (object); | |||
675 | } | |||
676 | ||||
677 | static void | |||
678 | sushi_font_widget_class_init (SushiFontWidgetClass *klass) | |||
679 | { | |||
680 | GObjectClass *oclass = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); | |||
681 | CtkWidgetClass *wclass = CTK_WIDGET_CLASS (klass)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), ((ctk_widget_get_type ())))))); | |||
682 | ||||
683 | oclass->finalize = sushi_font_widget_finalize; | |||
684 | oclass->set_property = sushi_font_widget_set_property; | |||
685 | oclass->get_property = sushi_font_widget_get_property; | |||
686 | oclass->constructed = sushi_font_widget_constructed; | |||
687 | ||||
688 | wclass->draw = sushi_font_widget_draw; | |||
689 | wclass->get_preferred_width = sushi_font_widget_get_preferred_width; | |||
690 | wclass->get_preferred_height = sushi_font_widget_get_preferred_height; | |||
691 | ||||
692 | properties[PROP_URI] = | |||
693 | g_param_spec_string ("uri", | |||
694 | "Uri", "Uri", | |||
695 | NULL((void*)0), G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | |||
696 | properties[PROP_FACE_INDEX] = | |||
697 | g_param_spec_int ("face-index", | |||
698 | "Face index", "Face index", | |||
699 | 0, G_MAXINT2147483647, | |||
700 | 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | |||
701 | ||||
702 | signals[LOADED] = | |||
703 | g_signal_new ("loaded", | |||
704 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), | |||
705 | G_SIGNAL_RUN_FIRST, | |||
706 | 0, NULL((void*)0), NULL((void*)0), | |||
707 | g_cclosure_marshal_VOID__VOID, | |||
708 | G_TYPE_NONE((GType) ((1) << (2))), 0); | |||
709 | signals[ERROR] = | |||
710 | g_signal_new ("error", | |||
711 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), | |||
712 | G_SIGNAL_RUN_FIRST, | |||
713 | 0, NULL((void*)0), NULL((void*)0), | |||
714 | g_cclosure_marshal_VOID__STRING, | |||
715 | G_TYPE_NONE((GType) ((1) << (2))), 1, G_TYPE_STRING((GType) ((16) << (2)))); | |||
716 | ||||
717 | g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); | |||
718 | } | |||
719 | ||||
720 | SushiFontWidget * | |||
721 | sushi_font_widget_new (const gchar *uri, gint face_index) | |||
722 | { | |||
723 | return g_object_new (SUSHI_TYPE_FONT_WIDGET(sushi_font_widget_get_type ()), | |||
724 | "uri", uri, | |||
725 | "face-index", face_index, | |||
726 | NULL((void*)0)); | |||
727 | } | |||
728 | ||||
729 | /** | |||
730 | * sushi_font_widget_get_ft_face: (skip) | |||
731 | * | |||
732 | */ | |||
733 | FT_Face | |||
734 | sushi_font_widget_get_ft_face (SushiFontWidget *self) | |||
735 | { | |||
736 | return self->priv->face; | |||
737 | } | |||
738 | ||||
739 | const gchar * | |||
740 | sushi_font_widget_get_uri (SushiFontWidget *self) | |||
741 | { | |||
742 | return self->priv->uri; | |||
743 | } | |||
744 |