/* gdkDPSfont.c --- DPS fonts representation in gdk * * This file is derived from gtkDPSfontpanel.c by * Masatake YAMATO. * * Copyright (C) 1998 Hideki FUJIMOTO * * Author: Hideki FUJIMOTO * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Font name and its file name collecting codes in thie file are comes from GNUstep... --- --- --- --- --- --- --- --- --- --- PXKFontManager.m NSFontManager for GNUstep GUI X/DPS Backend Copyright (C) 1996 Free Software Foundation, Inc. Author: Ovidiu Predescu Date: February 1997 A completely rewritten version of the original source of Scott Christley. This file is part of the GNUstep GUI X/DPS Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. --- --- --- --- --- --- --- --- --- --- */ #include "gdkDPSfont.h" #include "gdkDPS.h" #include "fonts.h" #include /* for FILENAME_MAX */ #include #include #include #include "parseAFM.h" static GSList * font_families_build_internal_structure (GHashTable * raw_table); static void font_families_build_internal_structure_callback(gpointer key, gpointer value, gpointer user_data); static GdkDPSTypeFace * gdk_dps_type_face_new(gchar * type_face, gchar * font_name); static gint gdk_dps_type_face_compare(GdkDPSTypeFace * t1, GdkDPSTypeFace * t2); static GdkDPSFontFamily * gdk_dps_font_family_new(gchar * family, GSList * type_faces_list); static void gdk_dps_font_family_update(GdkDPSFontFamily *, GSList * new_type_faces_list); static void gdk_dps_font_family_sort(GdkDPSFontFamily * font_family); static void gdk_dps_type_face_free(GdkDPSTypeFace *); static void gdk_dps_font_family_free(GdkDPSFontFamily *); static void gdk_dps_font_family_dump(GdkDPSFontFamily * font, gpointer usre_data); static void gdk_dps_type_face_dump(GdkDPSTypeFace * type_face, gpointer usre_data); static GHashTable * font_load_from_file (void); static GHashTable * font_load_from_server (); static int font_load_from_file_callback(char *resourceType, char *resourceName, char *resourceFile, char *user_data); static void font_load_from_server_callback_to_solve_aliases(gpointer key, gpointer value, gpointer user_data); static void font_load_from_server_callback_to_solve_path(gpointer key, gpointer value, gpointer user_data); static void font_load_from_server_callback_to_remove(gpointer data, gpointer user_data); static void gdk_dps_raw_table_element_dump(gpointer key, gpointer value, gpointer user_data); static void gdk_dps_fonts_raw_table_free_callback(gpointer key, gpointer value, gpointer user_data); static GdkDPSAFMFontInfo * gdk_dps_font_afm_font_info_new(gchar * file_name, int flags); static void gdk_dps_font_afm_font_info_free(GdkDPSAFMFontInfo * afm_font_info); GHashTable * gdk_dps_fonts_raw_table_get_shared (void) { /* TODO: Who will free the shared font table ? */ static GHashTable * shared_raw_table = NULL; if (shared_raw_table == NULL) shared_raw_table = gdk_dps_fonts_raw_table_new(); return shared_raw_table; } GHashTable * gdk_dps_fonts_raw_table_new (void) { GdkDPSAgentProduct product = gdk_dps_get_agent_product(); if (product == GDK_DPS_AGENT_PRODUCT_ADOBE_DPS) return font_load_from_file(); else return font_load_from_server(); } static GHashTable * font_load_from_file (void) { GHashTable * table = g_hash_table_new(g_str_hash, g_str_equal); EnumeratePSResourceFiles (NULL, NULL, PSResFontAFM, NULL, font_load_from_file_callback, (char *)table); if (0 == g_hash_table_size(table)) g_warning("No fonts were found! Check if the PSRESOURCEPATH " "environment variable points to the right directory. If so then " "probably you did not build the PS resource database using the " "`makepsres' utility."); return table; } static int font_load_from_file_callback(char *resourceType, char *resourceName, char *resourceFile, char *user_data) { gchar * font_name; GdkDPSAFMFontInfo * afm_font_info; GHashTable * table = (GHashTable * )user_data; g_return_val_if_fail(table, 0); afm_font_info = gdk_dps_font_afm_font_info_new(resourceFile, AFM_ALL); if (afm_font_info) { font_name = g_strdup(resourceName); g_hash_table_insert(table, font_name, afm_font_info); } return 0; } static GHashTable * font_load_from_server () { GHashTable * table = g_hash_table_new(g_str_hash, g_str_equal); char fontName[FILENAME_MAX + 1]; gchar * font_name_dupped; char fileOrFont[FILENAME_MAX + 1]; gchar * file_or_font_dupped; int noOfFonts; int i; GdkDPSContext * ctxt = gdk_dps_context_get_shared (); gdk_dps_context_begin(ctxt); { PSWFontNames (raw_ctxt, &noOfFonts); for (i = 0; i < noOfFonts; i++) { PSWGetFontsArray (raw_ctxt, fontName, fileOrFont); font_name_dupped = g_strdup (fontName); file_or_font_dupped = g_strdup (fileOrFont); g_hash_table_insert(table, font_name_dupped, file_or_font_dupped); } DPScleartomark (raw_ctxt); } gdk_dps_context_end(ctxt); /* Solve font name aliases */ g_hash_table_foreach (table, font_load_from_server_callback_to_solve_aliases, table); /* Solve AFM file path */ { GSList *remove_list = NULL; gpointer user_data[2]; user_data[0] = table; user_data[1] = &remove_list; g_hash_table_foreach (table, font_load_from_server_callback_to_solve_path, user_data); g_slist_foreach (remove_list, font_load_from_server_callback_to_remove, table); g_slist_free(remove_list); } return table; } static void font_load_from_server_callback_to_solve_aliases(gpointer key, gpointer value, gpointer user_data) { /* key -> value vlaue -> filename => key -> filename g_free(value); */ GHashTable * table = (GHashTable *)user_data; gpointer filename = g_hash_table_lookup(user_data, value); if (filename) { filename = g_strdup(filename); /* This will cause a bug ... Inserting a item in _foreach is OK? */ g_hash_table_insert(table, key, filename); g_free(value); } } static void font_load_from_server_callback_to_solve_path(gpointer key, gpointer value, gpointer user_data) { GHashTable * table = (GHashTable *)(((gpointer *)user_data)[0]); GSList * remove_list = *(GSList **)(((gpointer *)user_data)[1]); GdkDPSAFMFontInfo * afm_font_info; gchar completePath[FILENAME_MAX + 1]; gchar * tmp; gint found; gint i; GdkDPSContext * ctxt = gdk_dps_context_get_shared (); gdk_dps_context_begin(ctxt); PSWCompleteFilename (raw_ctxt, value, &found, completePath); gdk_dps_context_end(ctxt); /* * check Font file in full-path */ if (!found) { if (gdk_dps_debug_flags & GDK_DPS_DEBUG_FONT) g_message("Cannot solve the complete file path for the font: %s file: %s", (gchar *)key, (gchar *)value); remove_list = g_slist_prepend(remove_list, key); goto remove_list_and_exit; } /* * rewrite the suffix (e.g. gsf) of Font file * with AFM suffixes, and check existence */ tmp = strrchr(completePath, '.'); if (NULL == tmp) /* NULL pointer check for filename has no ".gsf" */ { if (gdk_dps_debug_flags & GDK_DPS_DEBUG_FONT) g_message("font file: %s has no correct suffix", (gchar *)value); remove_list = g_slist_prepend(remove_list, key); goto remove_list_and_exit; } /* originally: * tmp [1] = 'a'; tmp [2] = 'f'; tmp [3] = 'm'; tmp [4] = '\0'; * now try for all suffixes listed in afm_suffixes[] array. */ for (i = 0; NULL != afm_suffixes[i] ; i++) { strncpy(tmp, afm_suffixes[i], strlen(afm_suffixes[i])); afm_font_info = gdk_dps_font_afm_font_info_new(completePath, AFM_ALL); if (NULL != afm_font_info) /* AFM file found */ { g_hash_table_insert(table, key, afm_font_info); g_free(value); goto remove_list_and_exit; } else if (gdk_dps_debug_flags & GDK_DPS_DEBUG_FONT) { g_message("Cannot open AFM file: %s", completePath); } } /* * No corresponding AFM file found. */ if (gdk_dps_debug_flags & GDK_DPS_DEBUG_FONT) { g_message("Give up Font: %s lacking AFM file", (gchar *)key); } remove_list = g_slist_prepend(remove_list, key); remove_list_and_exit: *(GSList **)(((gpointer *)user_data)[1]) = remove_list; } static void font_load_from_server_callback_to_remove(gpointer data, gpointer user_data) { gpointer * value; value = g_hash_table_lookup(user_data, data); g_hash_table_remove(user_data, data); g_free(value); g_free(data); } static void gdk_dps_fonts_raw_table_free_callback(gpointer key, gpointer value, gpointer user_data) { g_free(key); gdk_dps_font_afm_font_info_free(value); } void gdk_dps_fonts_raw_table_free (GHashTable * table) { g_hash_table_foreach(table, gdk_dps_fonts_raw_table_free_callback, NULL); g_hash_table_destroy(table); } void gdk_dps_fonts_raw_table_dump (GHashTable * table, FILE * to) { g_return_if_fail(table); if (to == NULL) to = stderr; fprintf(stderr, "== FONT RAW TABLE ==\n"); g_hash_table_foreach(table, (GHFunc)gdk_dps_raw_table_element_dump, to); fprintf(stderr, "===================\n"); } static void gdk_dps_raw_table_element_dump(gpointer key, gpointer value, gpointer user_data) { FILE * to = user_data; GdkDPSAFMFontInfo * afm_font_info = value; fprintf(to, "fone name->%s, file name->%s\n", (gchar *)key, afm_font_info->file_name); } static void font_families_build_internal_structure_callback(gpointer key, gpointer value, gpointer user_data) { GSList * list = *(GSList **)user_data; gchar * font_name = g_strdup(key); list = g_slist_prepend(list, font_name); *(GSList **)user_data = list; } GSList * gdk_dps_font_families_list_new (GHashTable * raw_table) { GSList * font_families_list; gboolean free_raw_table = TRUE; if (raw_table == NULL) { raw_table = gdk_dps_fonts_raw_table_get_shared(); free_raw_table = FALSE; } #if 0 gdk_dps_fonts_raw_table_dump(raw_table, NULL); #endif /* 0 */ font_families_list = font_families_build_internal_structure(raw_table); if (free_raw_table == TRUE) gdk_dps_fonts_raw_table_free (raw_table); return font_families_list; } static gint strcmp_reverse(const gchar *s1, const gchar *s2) { gint tmp = strcmp(s1, s2); if (tmp == 0) return 0; else return -1 * tmp; } /* Make the structure of GdkDPSFontList */ static GSList * font_families_build_internal_structure (GHashTable * raw_table) { GSList * base_list = NULL; GSList * tmp_list; GSList *font_families_list = NULL; GdkDPSFontFamily * font_family = NULL; gchar *family_name_current; gchar *family_name_prev = NULL; GSList *type_face_list = NULL; gchar * type_face_name; GdkDPSTypeFace * type_face; GdkDPSAFMFontInfo * afm_font_info; g_hash_table_foreach(raw_table, font_families_build_internal_structure_callback, &base_list); base_list = g_slist_sort(base_list, (GCompareFunc)strcmp_reverse); for (tmp_list = base_list; tmp_list; tmp_list = g_slist_next(tmp_list)) { { gchar * font_name = tmp_list->data; tmp_list->data = NULL; afm_font_info = g_hash_table_lookup(raw_table, font_name); { gchar * tmp; /* family_name_current = g_strdup(afm_font_info->font_info->gfi->familyName); */ family_name_current = g_strdup(font_name); tmp = strchr(family_name_current, '-'); if (tmp) tmp[0] = '\0'; } if ( (NULL == afm_font_info->font_info->gfi->familyName) || (NULL == afm_font_info->font_info->gfi->fullName) || (0 == strcmp(afm_font_info->font_info->gfi->familyName, afm_font_info->font_info->gfi->fullName)) ) type_face_name = NULL; else { type_face_name = strlen(afm_font_info->font_info->gfi->familyName) + 1 + afm_font_info->font_info->gfi->fullName; type_face_name = g_strdup(type_face_name); } type_face = gdk_dps_type_face_new(type_face_name, font_name); } /* `family_prev' is holded a previous family name. */ if (family_name_prev && (strcmp (family_name_prev, family_name_current) == 0)) { g_free (family_name_current); family_name_current = NULL; type_face_list = g_slist_prepend(type_face_list, type_face); gdk_dps_font_family_update(font_family, type_face_list); } else { /* In case of diffrent family name, it should be allocate a new family name structure. */ type_face_list = g_slist_prepend(NULL, type_face); if (font_family) gdk_dps_font_family_sort(font_family); font_family = gdk_dps_font_family_new(family_name_current, type_face_list); font_families_list = g_slist_prepend(font_families_list, font_family); family_name_prev = family_name_current; } } g_slist_free(base_list); return font_families_list; } static GdkDPSTypeFace * gdk_dps_type_face_new(gchar * type_face, gchar * font_name) { GdkDPSTypeFace * tmp; /* g_return_val_if_fail (type_face, NULL); */ g_return_val_if_fail (font_name, NULL); tmp = g_new(GdkDPSTypeFace, 1); tmp->type_face = type_face; tmp->font_name = font_name; return tmp; } static GdkDPSFontFamily * gdk_dps_font_family_new(gchar * family_name, GSList * type_faces_list) { GdkDPSFontFamily * tmp; g_return_val_if_fail(family_name, NULL); g_return_val_if_fail(type_faces_list, NULL); tmp = g_new (GdkDPSFontFamily, 1); tmp->font_family = family_name; tmp->type_faces_list = type_faces_list; return tmp; } static void gdk_dps_font_family_update(GdkDPSFontFamily * font_family, GSList * new_type_faces_list) { g_return_if_fail(font_family); g_return_if_fail(new_type_faces_list); font_family->type_faces_list = new_type_faces_list; } static gint gdk_dps_type_face_compare(GdkDPSTypeFace * t1, GdkDPSTypeFace * t2) { g_return_val_if_fail(t1, 0); g_return_val_if_fail(t2, 0); if (t1->type_face == NULL) return -1; else if (t2->type_face == NULL) return 1; else return strcmp(t1->type_face, t2->type_face); } static void gdk_dps_font_family_sort(GdkDPSFontFamily * font_family) { g_return_if_fail(font_family); font_family->type_faces_list = g_slist_sort(font_family->type_faces_list, (GCompareFunc)gdk_dps_type_face_compare); } static void gdk_dps_type_face_free(GdkDPSTypeFace * face) { g_return_if_fail(face); g_return_if_fail(face->font_name); if (face->type_face != NULL) { g_free(face->type_face); face->type_face = NULL; } g_free(face->font_name); face->font_name = NULL; g_free(face); } static void gdk_dps_font_family_free_callback(GdkDPSTypeFace * face, gpointer user_data) { gdk_dps_type_face_free(face); } static void gdk_dps_font_family_free(GdkDPSFontFamily * font_family) { g_return_if_fail(font_family); g_return_if_fail(font_family->font_family); g_free(font_family->font_family); g_slist_foreach(font_family->type_faces_list, (GFunc) gdk_dps_font_family_free_callback, NULL); g_slist_free(font_family->type_faces_list); } static void gdk_dps_font_families_list_free_callback(GdkDPSFontFamily * font_family, gpointer user_data) { gdk_dps_font_family_free(font_family); } void gdk_dps_font_families_list_free (GSList * list) { g_return_if_fail(list); g_slist_foreach(list, (GFunc)gdk_dps_font_families_list_free_callback, NULL); g_slist_free(list); } /* * dump */ void gdk_dps_font_families_list_dump (GSList * list, FILE * to) { if (to == NULL) to = stderr; fprintf(to, "== FONT LIST ==\n"); g_slist_foreach(list, (GFunc)gdk_dps_font_family_dump, to); fprintf(to, "===============\n"); } static void gdk_dps_font_family_dump(GdkDPSFontFamily * font_family, gpointer usre_data) { FILE * to = (FILE *)usre_data; g_return_if_fail(font_family); g_return_if_fail(to); g_return_if_fail(font_family->font_family); fprintf(to, "Family name: %s\n", font_family->font_family); g_slist_foreach(font_family->type_faces_list, (GFunc)gdk_dps_type_face_dump, to); } static void gdk_dps_type_face_dump(GdkDPSTypeFace * type_face, gpointer usre_data) { FILE * to = (FILE *)usre_data; g_return_if_fail(type_face); g_return_if_fail(to); g_return_if_fail(type_face->font_name); fprintf(to, "\tType face: %s\n", type_face->type_face? type_face->type_face:" (void) "); fprintf(to, "\tFont name: %s\n", type_face->font_name); } static GdkDPSAFMFontInfo * gdk_dps_font_afm_font_info_new(gchar * file_name, int flags) { FILE * fp; GdkDPSAFMFontInfo * afm_font_info = NULL; g_return_val_if_fail(file_name, NULL); fp = fopen(file_name, "r"); if (fp) { afm_font_info = g_new(GdkDPSAFMFontInfo, 1); afm_font_info->file_name = g_strdup(file_name); AFMParseFile (fp, &(afm_font_info->font_info), flags); fclose(fp); } return afm_font_info; } static void gdk_dps_font_afm_font_info_free(GdkDPSAFMFontInfo * afm_font_info) { g_return_if_fail(afm_font_info); g_free(afm_font_info->file_name); afm_font_info->file_name = NULL; g_free(afm_font_info->font_info); /* TODO */ afm_font_info->font_info = NULL; }