4 * Copyright (C) 1999 Red Hat Software
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.
29 #include <glib/gstdio.h>
31 #include "pango-enum-types.h"
32 #include "pango-modules.h"
33 #include "pango-impl-utils.h"
36 typedef struct _PangoModule PangoModule;
37 typedef struct _PangoModuleClass PangoModuleClass;
39 #define PANGO_TYPE_MODULE (pango_module_get_type ())
40 #define PANGO_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), PANGO_TYPE_MODULE, PangoModule))
41 #define PANGO_IS_MODULE(module) (G_TYPE_CHECK_INSTANCE_TYPE ((module), PANGO_TYPE_MODULE))
43 typedef struct _PangoMapInfo PangoMapInfo;
44 typedef struct _PangoEnginePair PangoEnginePair;
45 typedef struct _PangoSubmap PangoSubmap;
60 PangoLanguage *language;
66 struct _PangoEnginePair
75 GTypeModule parent_instance;
80 void (*list) (PangoEngineInfo **engines, gint *n_engines);
81 void (*init) (GTypeModule *module);
83 PangoEngine *(*create) (const gchar *id);
86 struct _PangoModuleClass
88 GTypeModuleClass parent_class;
91 static GList *maps = NULL;
92 static GSList *registered_engines = NULL;
93 static GSList *dlloaded_engines = NULL;
94 static GHashTable *dlloaded_modules;
96 static GObjectClass *parent_class;
98 static void build_map (PangoMapInfo *info);
99 static void init_modules (void);
101 static GType pango_module_get_type (void);
105 * @language: the language tag for which to find the map
106 * @engine_type_id: the engine type for the map to find
107 * @render_type_id: the render type for the map to find
109 * Locate a #PangoMap for a particular engine type and render
110 * type. The resulting map can be used to determine the engine
111 * for each character.
113 * Return value: the suitable #PangoMap.
116 pango_find_map (PangoLanguage *language,
117 guint engine_type_id,
118 guint render_type_id)
120 GList *tmp_list = maps;
121 PangoMapInfo *map_info = NULL;
122 gboolean found_earlier = FALSE;
126 map_info = tmp_list->data;
127 if (map_info->engine_type_id == engine_type_id &&
128 map_info->render_type_id == render_type_id)
130 if (map_info->language == language)
133 found_earlier = TRUE;
136 tmp_list = tmp_list->next;
141 map_info = g_slice_new (PangoMapInfo);
142 map_info->language = language;
143 map_info->engine_type_id = engine_type_id;
144 map_info->render_type_id = render_type_id;
146 build_map (map_info);
148 maps = g_list_prepend (maps, map_info);
150 else if (found_earlier)
152 /* Move the found map to the beginning of the list
153 * for speed next time around if we had to do
154 * any failing comparison. (No longer so important,
155 * since we don't strcmp.)
157 maps = g_list_remove_link(maps, tmp_list);
158 maps = g_list_prepend(maps, tmp_list->data);
159 g_list_free_1(tmp_list);
162 return map_info->map;
166 pango_module_load (GTypeModule *module)
168 PangoModule *pango_module = PANGO_MODULE (module);
170 if (pango_module->path)
172 pango_module->library = g_module_open (pango_module->path, G_MODULE_BIND_LOCAL);
173 if (!pango_module->library)
175 g_warning ("%s", g_module_error());
179 /* extract symbols from the lib */
180 if (!g_module_symbol (pango_module->library, "script_engine_init",
181 (gpointer *)(void *)&pango_module->init) ||
182 !g_module_symbol (pango_module->library, "script_engine_exit",
183 (gpointer *)(void *)&pango_module->exit) ||
184 !g_module_symbol (pango_module->library, "script_engine_list",
185 (gpointer *)(void *)&pango_module->list) ||
186 !g_module_symbol (pango_module->library, "script_engine_create",
187 (gpointer *)(void *)&pango_module->create))
189 g_warning ("%s", g_module_error());
190 g_module_close (pango_module->library);
196 /* call the module's init function to let it */
197 /* setup anything it needs to set up. */
198 pango_module->init (module);
204 pango_module_unload (GTypeModule *module)
206 PangoModule *pango_module = PANGO_MODULE (module);
208 pango_module->exit();
210 if (pango_module->path)
212 g_module_close (pango_module->library);
213 pango_module->library = NULL;
215 pango_module->init = NULL;
216 pango_module->exit = NULL;
217 pango_module->list = NULL;
218 pango_module->create = NULL;
222 /* This only will ever be called if an error occurs during
226 pango_module_finalize (GObject *object)
228 PangoModule *module = PANGO_MODULE (object);
230 g_free (module->path);
232 parent_class->finalize (object);
236 pango_module_class_init (PangoModuleClass *class)
238 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
239 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
241 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class));
243 module_class->load = pango_module_load;
244 module_class->unload = pango_module_unload;
246 gobject_class->finalize = pango_module_finalize;
249 static PANGO_DEFINE_TYPE (PangoModule, pango_module,
250 pango_module_class_init, NULL,
254 pango_engine_pair_get_engine (PangoEnginePair *pair)
258 if (g_type_module_use (G_TYPE_MODULE (pair->module)))
260 pair->engine = pair->module->create (pair->info.id);
261 g_type_module_unuse (G_TYPE_MODULE (pair->module));
266 /* If a module cannot be used, or doesn't not create an engine
267 * correctly, we print out an error containing module name and id,
268 * but to not flood the terminal with zillions of the message, we
269 * set a flag on the module to only err once per module.
271 static GQuark warned_quark = 0;
274 warned_quark = g_quark_from_static_string ("pango-module-warned");
276 if (!g_object_get_qdata (G_OBJECT (pair->module), warned_quark))
278 g_warning ("Failed to load Pango module '%s' for id '%s'", pair->module->path, pair->info.id);
280 g_object_set_qdata_full (G_OBJECT (pair->module), warned_quark,
281 GINT_TO_POINTER (1), NULL);
290 handle_included_module (PangoIncludedModule *included_module,
291 GSList **engine_list)
293 PangoModule *module = g_object_new (PANGO_TYPE_MODULE, NULL);
294 PangoEngineInfo *engine_info;
298 module->list = included_module->list;
299 module->init = included_module->init;
300 module->exit = included_module->exit;
301 module->create = included_module->create;
303 module->list (&engine_info, &n_engines);
305 for (i = 0; i < n_engines; i++)
307 PangoEnginePair *pair = g_slice_new (PangoEnginePair);
309 pair->info = engine_info[i];
310 pair->module = module;
313 *engine_list = g_slist_prepend (*engine_list, pair);
318 find_or_create_module (const char *raw_path)
323 #if defined(G_OS_WIN32) && defined(LIBDIR)
324 if (strncmp (raw_path,
325 LIBDIR "/pango/" MODULE_VERSION "/modules/",
326 strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/")) == 0)
328 /* This is an entry put there by make install on the
329 * packager's system. On Windows a prebuilt Pango
330 * package can be installed in a random
331 * location. The pango.modules file distributed in
332 * such a package contains paths from the package
333 * builder's machine. Replace the path with the real
334 * one on this machine. */
336 g_strconcat (pango_get_lib_subdirectory (),
337 "\\" MODULE_VERSION "\\modules\\",
338 raw_path + strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/"),
344 path = g_strdup (raw_path);
347 module = g_hash_table_lookup (dlloaded_modules, path);
352 module = g_object_new (PANGO_TYPE_MODULE, NULL);
354 g_hash_table_insert (dlloaded_modules, path, module);
361 script_from_string (const char *str)
363 static GEnumClass *class = NULL;
366 class = g_type_class_ref (PANGO_TYPE_SCRIPT);
368 value = g_enum_get_value_by_nick (class, str);
370 return PANGO_SCRIPT_INVALID_CODE;
376 script_info_free (PangoEngineScriptInfo *script_info,
377 gpointer data G_GNUC_UNUSED)
379 g_slice_free (PangoEngineScriptInfo, script_info);
382 static gboolean /* Returns true if succeeded, false if failed */
383 process_module_file (FILE *module_file)
385 GString *line_buf = g_string_new (NULL);
386 GString *tmp_buf = g_string_new (NULL);
387 gboolean have_error = FALSE;
389 while (pango_read_line (module_file, line_buf))
391 PangoEnginePair *pair = g_slice_new (PangoEnginePair);
392 PangoEngineScriptInfo *script_info;
394 GList *scripts = NULL;
403 if (!pango_skip_space (&p))
405 g_slice_free (PangoEnginePair, pair);
412 if (!pango_scan_string (&p, tmp_buf))
421 pair->module = find_or_create_module (tmp_buf->str);
424 pair->info.id = g_strdup (tmp_buf->str);
427 pair->info.engine_type = g_strdup (tmp_buf->str);
430 pair->info.render_type = g_strdup (tmp_buf->str);
433 q = strchr (tmp_buf->str, ':');
440 script = script_from_string (tmp_buf->str);
441 if (script == PANGO_SCRIPT_INVALID_CODE)
447 script_info = g_slice_new (PangoEngineScriptInfo);
448 script_info->script = script;
449 script_info->langs = g_strdup (q + 1);
451 scripts = g_list_prepend (scripts, script_info);
454 if (!pango_skip_space (&p))
466 scripts = g_list_reverse (scripts);
467 pair->info.n_scripts = g_list_length (scripts);
468 pair->info.scripts = g_new (PangoEngineScriptInfo, pair->info.n_scripts);
471 for (i=0; i<pair->info.n_scripts; i++)
473 pair->info.scripts[i] = *(PangoEngineScriptInfo *)tmp_list->data;
474 tmp_list = tmp_list->next;
479 dlloaded_engines = g_slist_prepend (dlloaded_engines, pair);
482 g_list_foreach (scripts, (GFunc)script_info_free, NULL);
483 g_list_free (scripts);
487 g_printerr ("Error reading Pango modules file\n");
488 g_slice_free(PangoEnginePair, pair);
493 g_string_free (line_buf, TRUE);
494 g_string_free (tmp_buf, TRUE);
504 char *file_str = pango_config_key_get ("Pango/ModuleFiles");
508 dlloaded_modules = g_hash_table_new (g_str_hash, g_str_equal);
511 file_str = g_build_filename (pango_get_sysconf_subdirectory (),
515 files = pango_split_file_list (file_str);
523 module_file = g_fopen (files[n], "r");
526 process_module_file(module_file);
534 dlloaded_engines = g_slist_reverse (dlloaded_engines);
540 static gboolean init = FALSE;
548 /* Make sure that the type system is initialized */
551 for (i = 0; _pango_included_lang_modules[i].list; i++)
552 pango_module_register (&_pango_included_lang_modules[i]);
557 map_add_engine (PangoMapInfo *info,
558 PangoEnginePair *pair)
560 PangoMap *map = info->map;
563 for (i=0; i<pair->info.n_scripts; i++)
566 PangoMapEntry *entry;
567 gboolean is_exact = FALSE;
569 if (pair->info.scripts[i].langs)
571 if (pango_language_matches (info->language, pair->info.scripts[i].langs))
575 script = pair->info.scripts[i].script;
576 if ((guint)script >= map->entries->len)
577 g_array_set_size (map->entries, script + 1);
579 entry = &g_array_index (map->entries, PangoMapEntry, script);
582 entry->exact = g_slist_prepend (entry->exact, pair);
584 entry->fallback = g_slist_prepend (entry->fallback, pair);
589 map_add_engine_list (PangoMapInfo *info,
591 const char *engine_type,
592 const char *render_type)
594 GSList *tmp_list = engines;
598 PangoEnginePair *pair = tmp_list->data;
599 tmp_list = tmp_list->next;
601 if (strcmp (pair->info.engine_type, engine_type) == 0 &&
602 strcmp (pair->info.render_type, render_type) == 0)
604 map_add_engine (info, pair);
610 build_map (PangoMapInfo *info)
612 const char *engine_type = g_quark_to_string (info->engine_type_id);
613 const char *render_type = g_quark_to_string (info->render_type_id);
617 if (!dlloaded_engines && !registered_engines)
619 static gboolean no_module_warning = FALSE;
620 if (!no_module_warning)
622 gchar *filename = g_build_filename (pango_get_sysconf_subdirectory (),
625 g_critical ("No modules found:\n"
626 "No builtin or dynamically loaded modules were found.\n"
627 "PangoFc will not work correctly.\n"
628 "This probably means there was an error in the creation of:\n"
630 "You should create this file by running:\n"
631 " pango-querymodules > '%s'",
636 no_module_warning = TRUE;
640 info->map = g_slice_new (PangoMap);
641 info->map->entries = g_array_new (FALSE, TRUE, sizeof (PangoMapEntry));
643 map_add_engine_list (info, dlloaded_engines, engine_type, render_type);
644 map_add_engine_list (info, registered_engines, engine_type, render_type);
648 * pango_map_get_engine:
650 * @script: a #PangoScript
652 * Returns the best engine listed in the map for a given script
654 * Return value: the best engine, if one is listed for the script,
655 * or %NULL. The lookup may cause the engine to be loaded;
656 * once an engine is loaded, it won't be unloaded. If multiple
657 * engines are exact for the script, the choice of which is
658 * returned is arbitrary.
661 pango_map_get_engine (PangoMap *map,
664 PangoMapEntry *entry = NULL;
665 PangoMapEntry *common_entry = NULL;
667 if ((guint)script < map->entries->len)
668 entry = &g_array_index (map->entries, PangoMapEntry, script);
670 if (PANGO_SCRIPT_COMMON < map->entries->len)
671 common_entry = &g_array_index (map->entries, PangoMapEntry, PANGO_SCRIPT_COMMON);
673 if (entry && entry->exact)
674 return pango_engine_pair_get_engine (entry->exact->data);
675 else if (common_entry && common_entry->exact)
676 return pango_engine_pair_get_engine (common_entry->exact->data);
677 else if (entry && entry->fallback)
678 return pango_engine_pair_get_engine (entry->fallback->data);
679 else if (common_entry && common_entry->fallback)
680 return pango_engine_pair_get_engine (common_entry->fallback->data);
686 append_engines (GSList **engine_list,
691 for (l = pair_list; l; l = l->next)
693 PangoEngine *engine = pango_engine_pair_get_engine (l->data);
695 *engine_list = g_slist_append (*engine_list, engine);
700 * pango_map_get_engines:
702 * @script: a #PangoScript
703 * @exact_engines: location to store list of engines that exactly
704 * handle this script.
705 * @fallback_engines: location to store list of engines that approximately
706 * handle this script.
708 * Finds engines in the map that handle the given script. The returned
709 * lists should be freed with g_slist_free, but the engines in the
710 * lists are owned by GLib and will be kept around permanently, so
711 * they should not be unref'ed.
716 pango_map_get_engines (PangoMap *map,
718 GSList **exact_engines,
719 GSList **fallback_engines)
721 PangoMapEntry *entry = NULL;
722 PangoMapEntry *common_entry = NULL;
724 if ((guint)script < map->entries->len)
725 entry = &g_array_index (map->entries, PangoMapEntry, script);
727 if (PANGO_SCRIPT_COMMON < map->entries->len)
728 common_entry = &g_array_index (map->entries, PangoMapEntry, PANGO_SCRIPT_COMMON);
732 *exact_engines = NULL;
733 if (entry && entry->exact)
734 append_engines (exact_engines, entry->exact);
735 else if (common_entry && common_entry->exact)
736 append_engines (exact_engines, common_entry->exact);
739 if (fallback_engines)
741 *fallback_engines = NULL;
742 if (entry && entry->fallback)
743 append_engines (fallback_engines, entry->fallback);
744 else if (common_entry && common_entry->fallback)
745 append_engines (fallback_engines, common_entry->fallback);
750 * pango_module_register:
751 * @module: a #PangoIncludedModule
753 * Registers a statically linked module with Pango. The
754 * #PangoIncludedModule structure that is passed in contains the
755 * functions that would otherwise be loaded from a dynamically loaded
759 pango_module_register (PangoIncludedModule *module)
761 GSList *tmp_list = NULL;
763 handle_included_module (module, &tmp_list);
765 registered_engines = g_slist_concat (registered_engines,
766 g_slist_reverse (tmp_list));