1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library.
3 *
4 * Copyright (C) 2000 Helix Code, Inc.
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 License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include <config.h>
23 #include <string.h>
24 #include <pango/pango.h>
25
26 #include "gtkhtmlfontstyle.h"
27 #include "htmlfontmanager.h"
28 #include "htmlpainter.h"
29 #include "htmlengine.h"
30
31 static void
html_font_set_init(HTMLFontSet * set,gchar * face)32 html_font_set_init (HTMLFontSet *set,
33 gchar *face)
34 {
35 memset (set, 0, GTK_HTML_FONT_STYLE_MAX_FONT * sizeof (HTMLFont *));
36 set->ref_count = 1;
37 set->face = g_strdup (face);
38 }
39
40 static HTMLFontSet *
html_font_set_new(gchar * face)41 html_font_set_new (gchar *face)
42 {
43 HTMLFontSet *set;
44
45 set = g_new (HTMLFontSet, 1);
46 html_font_set_init (set, face);
47
48 return set;
49 }
50
51 static gboolean
html_font_set_face(HTMLFontSet * set,gchar * face)52 html_font_set_face (HTMLFontSet *set,
53 gchar *face)
54 {
55 if (!set->face || strcmp (set->face, face)) {
56 if (set->face)
57 g_free (set->face);
58 set->face = g_strdup (face);
59 return TRUE;
60 }
61 return FALSE;
62 }
63
64 static void
html_font_set_release(HTMLFontSet * set,HTMLPainter * painter)65 html_font_set_release (HTMLFontSet *set,
66 HTMLPainter *painter)
67 {
68 gint i;
69
70 for (i = 0; i < GTK_HTML_FONT_STYLE_MAX_FONT; i++) {
71 if (set->font[i])
72 html_font_unref (set->font[i], painter);
73 set->font[i] = NULL;
74 }
75 }
76
77 static void
html_font_set_unref(HTMLFontSet * set,HTMLPainter * painter)78 html_font_set_unref (HTMLFontSet *set,
79 HTMLPainter *painter)
80 {
81 set->ref_count--;
82 if (!set->ref_count) {
83 html_font_set_release (set, painter);
84 if (set->face)
85 g_free (set->face);
86
87 g_free (set);
88 }
89 }
90
91 void
html_font_manager_init(HTMLFontManager * manager,HTMLPainter * painter)92 html_font_manager_init (HTMLFontManager *manager,
93 HTMLPainter *painter)
94 {
95 manager->font_sets = g_hash_table_new (g_str_hash, g_str_equal);
96 manager->var_size = 12 * PANGO_SCALE;
97 manager->var_points = FALSE;
98 manager->fix_size = 12 * PANGO_SCALE;
99 manager->fix_points = FALSE;
100 manager->magnification = 1.0;
101 manager->painter = painter;
102
103 html_font_set_init (&manager->variable, NULL);
104 html_font_set_init (&manager->fixed, NULL);
105 }
106
107 void
html_font_manager_set_magnification(HTMLFontManager * manager,gdouble magnification)108 html_font_manager_set_magnification (HTMLFontManager *manager,
109 gdouble magnification)
110 {
111 g_return_if_fail (magnification > 0.0);
112
113 if (magnification != manager->magnification) {
114 manager->magnification = magnification;
115 html_font_manager_clear_font_cache (manager);
116 }
117 }
118
119 static gboolean
destroy_font_set_foreach(gpointer key,gpointer font_set,gpointer data)120 destroy_font_set_foreach (gpointer key,
121 gpointer font_set,
122 gpointer data)
123 {
124 g_free (key);
125 html_font_set_unref (font_set, HTML_PAINTER (data));
126
127 return TRUE;
128 }
129
130 static void
clear_additional_font_sets(HTMLFontManager * manager)131 clear_additional_font_sets (HTMLFontManager *manager)
132 {
133 g_hash_table_foreach_remove (manager->font_sets, destroy_font_set_foreach, manager->painter);
134 }
135
136 void
html_font_manager_clear_font_cache(HTMLFontManager * manager)137 html_font_manager_clear_font_cache (HTMLFontManager *manager)
138 {
139 html_font_set_release (&manager->variable, manager->painter);
140 html_font_set_release (&manager->fixed, manager->painter);
141 clear_additional_font_sets (manager);
142 }
143
144 void
html_font_manager_finalize(HTMLFontManager * manager)145 html_font_manager_finalize (HTMLFontManager *manager)
146 {
147 html_font_set_release (&manager->variable, manager->painter);
148 html_font_set_release (&manager->fixed, manager->painter);
149 g_free (manager->fixed.face);
150 g_free (manager->variable.face);
151
152 clear_additional_font_sets (manager);
153 g_hash_table_destroy (manager->font_sets);
154 }
155
156 void
html_font_manager_set_default(HTMLFontManager * manager,gchar * variable,gchar * fixed,gint var_size,gboolean var_points,gint fix_size,gboolean fix_points)157 html_font_manager_set_default (HTMLFontManager *manager,
158 gchar *variable,
159 gchar *fixed,
160 gint var_size,
161 gboolean var_points,
162 gint fix_size,
163 gboolean fix_points)
164 {
165 gboolean changed = FALSE;
166
167 /* variable width fonts */
168 changed = html_font_set_face (&manager->variable, variable);
169 if (manager->var_size != var_size || manager->var_points != var_points) {
170 manager->var_size = var_size;
171 manager->var_points = var_points;
172 clear_additional_font_sets (manager);
173 changed = TRUE;
174 }
175
176 if (changed) {
177 html_font_set_release (&manager->variable, manager->painter);
178 }
179
180 /* fixed width fonts */
181 changed = html_font_set_face (&manager->fixed, fixed);
182 if (manager->fix_size != fix_size || manager->fix_points != fix_points) {
183 manager->fix_size = fix_size;
184 manager->fix_points = fix_points;
185 changed = TRUE;
186 }
187
188 if (changed) {
189 /*
190 * NOTE we clear both if fixed changes because the plain painter pulls nasty
191 * tricks with using fixed fonts in the variable manager so if the fixed font
192 * change the variable font may change too.
193 * */
194 html_font_set_release (&manager->variable, manager->painter);
195 html_font_set_release (&manager->fixed, manager->painter);
196 }
197 }
198
199 static gint
get_font_num(GtkHTMLFontStyle style)200 get_font_num (GtkHTMLFontStyle style)
201 {
202 style |= (style & GTK_HTML_FONT_STYLE_SIZE_MASK) ? 0 : GTK_HTML_FONT_STYLE_SIZE_3;
203
204 return (style & GTK_HTML_FONT_STYLE_MAX_FONT_MASK);
205 }
206
207 static gint
html_font_set_get_idx(GtkHTMLFontStyle style)208 html_font_set_get_idx (GtkHTMLFontStyle style)
209 {
210 return get_font_num (style) - 1;
211 }
212
213 static HTMLFontSet *
get_font_set(HTMLFontManager * manager,gchar * face,GtkHTMLFontStyle style)214 get_font_set (HTMLFontManager *manager,
215 gchar *face,
216 GtkHTMLFontStyle style)
217 {
218 return (face)
219 ? g_hash_table_lookup (manager->font_sets, face)
220 : ((style & GTK_HTML_FONT_STYLE_FIXED) ? &manager->fixed : &manager->variable);
221 }
222
223 static gdouble
get_real_font_size(HTMLFontManager * manager,GtkHTMLFontStyle style)224 get_real_font_size (HTMLFontManager *manager,
225 GtkHTMLFontStyle style)
226 {
227 gint size = (get_font_num (style) & GTK_HTML_FONT_STYLE_SIZE_MASK) - GTK_HTML_FONT_STYLE_SIZE_3;
228 gint base_size = style & GTK_HTML_FONT_STYLE_FIXED ? manager->fix_size : manager->var_size;
229
230 return manager->magnification * (base_size + (size > 0 ? (1 << size) : size) * base_size / 8.0);
231 }
232
233 static void
html_font_set_font(HTMLFontManager * manager,HTMLFontSet * set,GtkHTMLFontStyle style,HTMLFont * font)234 html_font_set_font (HTMLFontManager *manager,
235 HTMLFontSet *set,
236 GtkHTMLFontStyle style,
237 HTMLFont *font)
238 {
239 gint idx;
240
241 g_assert (font);
242 g_assert (set);
243
244 /* set font in font set */
245 idx = html_font_set_get_idx (style);
246 if (set->font[idx] && font != set->font[idx])
247 html_font_unref (set->font[idx], manager->painter);
248 set->font[idx] = font;
249 }
250
251 static HTMLFont *
get_font(HTMLFontManager * manager,HTMLFontSet ** set,gchar * face,GtkHTMLFontStyle style)252 get_font (HTMLFontManager *manager,
253 HTMLFontSet **set,
254 gchar *face,
255 GtkHTMLFontStyle style)
256 {
257 HTMLFont *font = NULL;
258
259 *set = get_font_set (manager, face, style);
260 if (*set)
261 font = (*set)->font[html_font_set_get_idx (style)];
262 return font;
263 }
264
265 gchar *
html_font_manager_get_attr(gchar * font_name,gint n)266 html_font_manager_get_attr (gchar *font_name,
267 gint n)
268 {
269 gchar *s, *end;
270
271 /* Search paramether */
272 for (s = font_name; n; n--,s++)
273 s = strchr (s,'-');
274
275 if (s && *s != 0) {
276 end = strchr (s, '-');
277 if (end)
278 return g_strndup (s, end - s);
279 else
280 return g_strdup (s);
281 } else
282 return g_strdup ("Unknown");
283 }
284
285 static gboolean
get_points(HTMLFontManager * manager,GtkHTMLFontStyle style)286 get_points (HTMLFontManager *manager,
287 GtkHTMLFontStyle style)
288 {
289 return (style & GTK_HTML_FONT_STYLE_FIXED) ? manager->fix_points : manager->var_points;
290 }
291
292 static gpointer
manager_alloc_font(HTMLFontManager * manager,gchar * face,GtkHTMLFontStyle style)293 manager_alloc_font (HTMLFontManager *manager,
294 gchar *face,
295 GtkHTMLFontStyle style)
296 {
297 return html_painter_alloc_font (manager->painter, face, get_real_font_size (manager, style), get_points (manager, style), style);
298 }
299
300 static gchar *
strip_white_space(gchar * name)301 strip_white_space (gchar *name)
302 {
303 gint end;
304 while (name[0] == ' ' || name[0] == '\t')
305 name++;
306 end = strlen (name);
307 while (end && (name[end - 1] == ' ' || name[end - 1] == '\t')) {
308 name[end - 1] = 0;
309 end--;
310 }
311
312 return name;
313 }
314
315 static HTMLFont *
alloc_new_font(HTMLFontManager * manager,HTMLFontSet ** set,gchar * face_list,GtkHTMLFontStyle style)316 alloc_new_font (HTMLFontManager *manager,
317 HTMLFontSet **set,
318 gchar *face_list,
319 GtkHTMLFontStyle style)
320 {
321 HTMLFont *font = NULL;
322 gchar **faces;
323 gchar **face;
324
325 if (!(*set)) {
326 face = faces = g_strsplit (face_list, ",", 0);
327 while (*face) {
328 gchar *face_name = strip_white_space (*face);
329
330 /* first try to get font from available sets */
331 font = get_font (manager, set, face_name, style);
332 if (!font)
333 font = manager_alloc_font (manager, face_name, style);
334 if (font) {
335 if (!(*set)) {
336 *set = html_font_set_new (face_name);
337 g_hash_table_insert (manager->font_sets, g_strdup (face_name), *set);
338 }
339 if (strcmp (face_list, *face)) {
340 (*set)->ref_count++;
341 g_hash_table_insert (manager->font_sets, g_strdup (face_list), *set);
342 }
343 break;
344 }
345 face++;
346 }
347 g_strfreev (faces);
348 if (!(*set)) {
349 /* none of faces exist, so create empty set for him and let manager later set fixed font here */
350 *set = html_font_set_new (face_list);
351 g_hash_table_insert (manager->font_sets, g_strdup (face_list), *set);
352 }
353 } else
354 font = manager_alloc_font (manager, (*set)->face, style);
355
356 if ((*set) && font)
357 html_font_set_font (manager, (*set), style, font);
358
359 return font;
360 }
361
362 HTMLFont *
html_font_manager_get_font(HTMLFontManager * manager,gchar * face_list,GtkHTMLFontStyle style)363 html_font_manager_get_font (HTMLFontManager *manager,
364 gchar *face_list,
365 GtkHTMLFontStyle style)
366 {
367 HTMLFontSet *set;
368 HTMLFont *font = NULL;
369
370 font = get_font (manager, &set, face_list, style);
371
372 if (!font) {
373 /* first try to alloc right one */
374 font = alloc_new_font (manager, &set, face_list, style);
375 if (!font) {
376 g_assert (set);
377 if (!face_list) {
378 /* default font, so the last chance is to get fixed font */
379 font = html_painter_alloc_font (manager->painter, NULL,
380 get_real_font_size (manager, style),
381 get_points (manager, style), style);
382 if (!font)
383 g_warning ("Cannot allocate fixed font\n");
384 } else {
385 /* some unavailable non-default font => use default one */
386
387 font = html_font_manager_get_font (manager, NULL, style);
388 html_font_ref (font, manager->painter);
389 }
390 if (font)
391 html_font_set_font (manager, set, style, font);
392 }
393 }
394
395 return font;
396 }
397
398 HTMLFont *
html_font_new(gpointer data,guint space_width,guint space_asc,guint space_dsc,guint nbsp_width,guint tab_width,guint e_width,guint indent_width,guint cite_width_ltr,guint cite_width_rtl)399 html_font_new (gpointer data,
400 guint space_width,
401 guint space_asc,
402 guint space_dsc,
403 guint nbsp_width,
404 guint tab_width,
405 guint e_width,
406 guint indent_width,
407 guint cite_width_ltr,
408 guint cite_width_rtl)
409 {
410 HTMLFont *font = g_new (HTMLFont, 1);
411
412 font->data = data;
413 font->space_width = space_width;
414 font->space_asc = space_asc;
415 font->space_dsc = space_dsc;
416 font->nbsp_width = nbsp_width;
417 font->tab_width = tab_width;
418 font->e_width = e_width;
419 font->indent_width = indent_width;
420 font->cite_width_ltr = cite_width_ltr;
421 font->cite_width_rtl = cite_width_rtl;
422 font->ref_count = 1;
423
424 return font;
425 }
426
427 void
html_font_destroy(HTMLFont * font)428 html_font_destroy (HTMLFont *font)
429 {
430 g_free (font);
431 }
432
433 void
html_font_ref(HTMLFont * font,HTMLPainter * painter)434 html_font_ref (HTMLFont *font,
435 HTMLPainter *painter)
436 {
437 html_painter_ref_font (painter, font);
438 font->ref_count++;
439 }
440
441 void
html_font_unref(HTMLFont * font,HTMLPainter * painter)442 html_font_unref (HTMLFont *font,
443 HTMLPainter *painter)
444 {
445 font->ref_count--;
446 html_painter_unref_font (painter, font);
447
448 if (font->ref_count < 1)
449 html_font_destroy (font);
450 }
451