1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "gretl.h"
21 #include "fontfilter.h"
22 
23 #define FONT_DEBUG 0
24 
25 static GtkWidget *font_test_widget;
26 static PangoContext *font_test_context;
27 static PangoLanguage *font_test_lang;
28 
gretl_font_filter_init(void)29 int gretl_font_filter_init (void)
30 {
31     font_test_widget = gtk_label_new(NULL);
32     font_test_context = gtk_widget_get_pango_context(font_test_widget);
33 
34     if (font_test_context == NULL) {
35 	gtk_widget_destroy(font_test_widget);
36 	font_test_widget = NULL;
37 	return 1;
38     }
39 
40     font_test_lang = pango_language_from_string("eng");
41     if (font_test_lang == NULL) {
42 	gretl_font_filter_cleanup();
43 	return 1;
44     }
45 
46     return 0;
47 }
48 
gretl_font_filter_cleanup(void)49 void gretl_font_filter_cleanup (void)
50 {
51     if (font_test_context != NULL) {
52 	g_object_unref(G_OBJECT(font_test_context));
53 	font_test_context = NULL;
54     }
55     if (font_test_widget != NULL) {
56 	gtk_widget_destroy(font_test_widget);
57 	font_test_widget = NULL;
58     }
59 }
60 
61 enum {
62     HACK_LATIN_FONT = 1 << 0,
63     HACK_MONO_FONT  = 1 << 1,
64     HACK_WEIRD_FONT = 1 << 2
65 };
66 
67 /* We test a font for "latin text" compatibility, via the heuristic
68    of seeing if it contains the letters 'i' and 'W' in English.  Given the
69    latin text characteristic, we then see if the font is monospaced
70    using pango_font_family_is_monospace().
71 */
72 
get_font_characteristics(PangoFontFamily * family,PangoFontDescription * desc)73 static int get_font_characteristics (PangoFontFamily *family,
74 				     PangoFontDescription *desc)
75 {
76     PangoFont *font;
77     int ret = 0;
78 
79     font = pango_context_load_font(font_test_context, desc);
80 
81     if (font != NULL) {
82 	PangoCoverage *coverage;
83 
84 	coverage = pango_font_get_coverage(font, font_test_lang);
85 	if (coverage != NULL) {
86 	    if (pango_coverage_get(coverage, 'i') == PANGO_COVERAGE_EXACT &&
87 		pango_coverage_get(coverage, 'W') == PANGO_COVERAGE_EXACT) {
88 		ret = HACK_LATIN_FONT;
89 		if (pango_font_family_is_monospace(family)) {
90 		    ret |= HACK_MONO_FONT;
91 		}
92 	    }
93 	    pango_coverage_unref(coverage);
94 	}
95 	g_object_unref(font);
96     }
97 
98 #if FONT_DEBUG
99     fprintf(stderr, " latin %s, monospaced %s\n",
100 	    (ret & HACK_LATIN_FONT)? "yes" : "no",
101 	    (ret & HACK_MONO_FONT)? "yes" : "no");
102 #endif
103 
104     return ret;
105 }
106 
font_progress_bar(int i,int nf)107 static void font_progress_bar (int i, int nf)
108 {
109     static int (*show_progress) (double, double, int) = NULL;
110     static int show = 1;
111 
112     if (show && show_progress == NULL) {
113 	show_progress = gui_get_plugin_function("show_progress");
114 	if (show_progress == NULL) {
115 	    show = 0;
116 	} else {
117 	    (*show_progress)(0, nf, SP_FONT_INIT);
118 	}
119     }
120 
121     if (show) {
122 	if (i == nf - 1) {
123 	    (*show_progress)(0, nf, SP_FINISH);
124 	    show = 0;
125 	} else if (i > 0) {
126 	    (*show_progress)(1, nf, SP_NONE);
127 	}
128     }
129 }
130 
131 #define weird_font(s) (strstr(s, "arioso") || \
132                        strstr(s, "dings") || \
133                        strstr(s, "ancery"))
134 
135 /* If we're on the first run, check the font's characteristics and
136    cache the info.  Otherwise just read off the information we cached
137    previously.  In either case, return non-zero iff the font validates
138    in respect of the criterion in @filter.
139 */
140 
validate_font_family(PangoFontFamily * family,const gchar * famname,gint i,gint nf,gint filter,gint * err)141 int validate_font_family (PangoFontFamily *family,
142 			  const gchar *famname,
143 			  gint i, gint nf,
144 			  gint filter, gint *err)
145 {
146     static char *fcache;
147     static int build_cache;
148     int ret;
149 
150     if (i >= nf) {
151 	fprintf(stderr, "validate_font_family: got excess font!\n");
152 	return 0;
153     }
154 
155     if (fcache == NULL) {
156 	fcache = calloc(nf, 1);
157 	if (fcache == NULL) {
158 	    *err = 1;
159 	    return 0;
160 	}
161 	build_cache = 1;
162 	gretl_font_filter_init();
163     }
164 
165     if (build_cache) {
166 #if FONT_DEBUG
167 	fprintf(stderr, "Checking font family %d, '%s'\n", i, famname);
168 #endif
169 	font_progress_bar(i, nf);
170 	if (weird_font(famname)) {
171 	    fcache[i] = HACK_WEIRD_FONT;
172 	} else {
173 	    gchar *fontname = g_strdup_printf("%s 10", famname);
174 	    PangoFontDescription *desc =
175 		pango_font_description_from_string(fontname);
176 
177 	    if (desc != NULL) {
178 		fcache[i] = get_font_characteristics(family, desc);
179 		pango_font_description_free(desc);
180 	    }
181 	    g_free(fontname);
182 	}
183     }
184 
185     if (build_cache && i == nf - 1) {
186 	gretl_font_filter_cleanup();
187 	build_cache = 0;
188     }
189 
190     if (filter == FONT_FILTER_LATIN) {
191 	ret = fcache[i] & HACK_LATIN_FONT;
192     } else if (filter == FONT_FILTER_LATIN_MONO) {
193 	ret = fcache[i] & HACK_MONO_FONT;
194     } else {
195 	ret = !(fcache[i] & HACK_WEIRD_FONT);
196     }
197 
198     return ret;
199 }
200 
validate_single_font(const PangoFontFamily * family,gint filter)201 int validate_single_font (const PangoFontFamily *family,
202 			  gint filter)
203 {
204     const gchar *famname =
205 	pango_font_family_get_name((PangoFontFamily *) family);
206     int ret, fc = 0;
207 
208 #if FONT_DEBUG
209     fprintf(stderr, "Checking font '%s'\n", famname);
210 #endif
211 
212     if (weird_font(famname)) {
213 	fc = HACK_WEIRD_FONT;
214     } else {
215 	gchar *font = g_strdup_printf("%s 10", famname);
216 	PangoFontDescription *desc = pango_font_description_from_string(font);
217 
218 	if (desc != NULL) {
219 	    fc = get_font_characteristics((PangoFontFamily *) family, desc);
220 	    pango_font_description_free(desc);
221 	}
222 	g_free(font);
223     }
224 
225 
226     if (filter == FONT_FILTER_LATIN) {
227 	ret = fc & HACK_LATIN_FONT;
228     } else if (filter == FONT_FILTER_LATIN_MONO) {
229 	ret = fc & HACK_MONO_FONT;
230     } else {
231 	ret = !(fc & HACK_WEIRD_FONT);
232     }
233 
234     return ret;
235 }
236