/* A first attempt to set up a font selection scheme for mozilla * Perhaps this should be put in a seperate widget, who knows. * This code is a massive rip off from the GTK Font Selector widget. * The font look up is probably not as efficient as it ought to be... * Moz_font_select: code for selecting fonts in mozilla * Based on GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998. * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes. * The GnomeFontSelector was derived from app/text_tool.c in the GIMP. */ #include "gdk/gdktypes.h" #include "gdk/gdkx.h" #include "gdk/gdkkeysyms.h" #include #include "xp_core.h" #define Bool char #include #include #define Bool char #include "xpassert.h" #include "g-font-select.h" #define MAX_FONTS 32767 /* This is the number of properties which we keep in the properties array, i.e. Weight, Slant, Set Width, Spacing, Charset & Foundry. */ #define NUM_FONT_PROPERTIES 6 /* This is the number of properties each style has i.e. Weight, Slant, Set Width, Spacing & Charset. Note that Foundry is not included, since it is the same for all styles of the same FontInfo. */ #define NUM_STYLE_PROPERTIES 5 /* This is the largest field length we will accept. If a fontname has a field larger than this we will skip it. */ #define XLFD_MAX_FIELD_LEN 64 /* This is the number of fields in an X Logical Font Description font name. Note that we count the registry & encoding as 1. */ #define XLFD_NUM_FIELDS 13 /* Used for the flags field in FontStyle. Note that they can be combined, e.g. a style can have multiple bitmaps and a true scalable version. The displayed flag is used when displaying styles to remember which styles have already been displayed. */ enum { BITMAP_FONT = 1 << 0, SCALABLE_FONT = 1 << 1, SCALABLE_BITMAP_FONT = 1 << 2, DISPLAYED = 1 << 3 }; typedef struct _FontSelInfo FontSelInfo; typedef struct _FontStyle FontStyle; typedef struct _MozFontInfo MozFontInfo; /* This struct represents one family of fonts (with one foundry), e.g. adobe courier or sony fixed. It stores the family name, the index of the foundry name, and the index of and number of available styles. */ /* This represents one style, as displayed in the Font Style clist. It can have a number of available pixel sizes and point sizes. The indexes point into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes arrays. */ struct _FontStyle { guint16 properties[NUM_STYLE_PROPERTIES]; gint pixel_sizes_index; guint16 npixel_sizes; gint point_sizes_index; guint16 npoint_sizes; guint8 flags; }; struct _MozFontInfo { gchar *family; guint16 foundry; gint style_index; guint16 nstyles; }; struct _FontSelInfo { MozFontInfo *font_info; gint nfonts; /* This stores all the valid combinations of properties for every family. Each FontInfo holds an index into its own space in this one big array. */ FontStyle *font_styles; gint nstyles; /* This stores all the font sizes available for every style. Each style holds an index into these arrays. */ guint16 *pixel_sizes; guint16 *point_sizes; /* These are the arrays of strings of all possible weights, slants, set widths, spacings, charsets & foundries, and the amount of space allocated for each array. */ gchar **properties[NUM_FONT_PROPERTIES]; guint16 nproperties[NUM_FONT_PROPERTIES]; guint16 space_allocated[NUM_FONT_PROPERTIES]; /* Whether any scalable bitmap fonts are available. If not, the 'Allow scaled bitmap fonts' toggle button is made insensitive. */ gboolean scaled_bitmaps_available; }; typedef enum { XLFD_FOUNDRY = 0, XLFD_FAMILY = 1, XLFD_WEIGHT = 2, XLFD_SLANT = 3, XLFD_SET_WIDTH = 4, XLFD_ADD_STYLE = 5, XLFD_PIXELS = 6, XLFD_POINTS = 7, XLFD_RESOLUTION_X = 8, XLFD_RESOLUTION_Y = 9, XLFD_SPACING = 10, XLFD_AVERAGE_WIDTH = 11, XLFD_CHARSET = 12 } FontField; typedef enum { METRIC_PIXEL = 0, METRIC_POINT = 1, } MozFontMetric; /* These are the names of the fields, used on the info & filter page. */ static gchar* xlfd_field_names[XLFD_NUM_FIELDS] = { "Foundry:", "Family:", "Weight:", "Slant:", "Set Width:", "Add Style:", "Pixel Size:", "Point Size:", "Resolution X:", "Resolution Y:", "Spacing:", "Average Width:", "Charset:", }; /* These are the array indices of the font properties used in several arrays, and should match the xlfd_index array below. */ typedef enum { WEIGHT = 0, SLANT = 1, SET_WIDTH = 2, SPACING = 3, CHARSET = 4, FOUNDRY = 5 } PropertyIndexType; /* This is used to look up a field in a fontname given one of the above property indices. */ static FontField xlfd_index[NUM_FONT_PROPERTIES] = { XLFD_WEIGHT, XLFD_SLANT, XLFD_SET_WIDTH, XLFD_SPACING, XLFD_CHARSET, XLFD_FOUNDRY }; /* The initial size and increment of each of the arrays of property values. */ #define PROPERTY_ARRAY_INCREMENT 16 /* prototypes */ static gchar* moz_get_xlfd_field (const gchar *fontname, FontField field_num, gchar *buffer); static gint moz_insert_field (gchar *fontname, gint prop); static gboolean moz_xlfd_font_name (const gchar *fontname); static void moz_insert_font (GSList *fontnames[], gint *ntable, gchar *fontname); static char * NameFromList(char *namelist); /**/ static FontSelInfo *fontsel_info = NULL; /* initialize the fontselinfo struct */ void moz_font_init() { gchar **xfontnames; GSList **fontnames; gchar *fontname; GSList * temp_list; gint num_fonts; gint i, prop, style, size; gint npixel_sizes = 0, npoint_sizes = 0; MozFontInfo *font; FontStyle *current_style, *prev_style, *tmp_style; gboolean matched_style, found_size; gint pixels, points, res_x, res_y; gchar field_buffer[XLFD_MAX_FIELD_LEN]; gchar *field; guint8 flags; guint16 *pixel_sizes, *point_sizes, *tmp_sizes; fontsel_info = g_new(FontSelInfo, 1); xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts); if (num_fonts == MAX_FONTS) { g_warning("Maximum number of fonsts exceeded."); } /* Are MozFontInfo etc defined? */ fontsel_info->font_info = g_new (MozFontInfo, num_fonts); fontsel_info->font_styles = g_new (FontStyle, num_fonts); fontsel_info->pixel_sizes = g_new (guint16, num_fonts); fontsel_info->point_sizes = g_new (guint16, num_fonts); fontnames = g_new (GSList*, num_fonts); /* idem for NUM_FONT_PROPERTIES etc */ for (prop = 0; prop < NUM_FONT_PROPERTIES; prop++) { fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT); fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT; fontsel_info->nproperties[prop] = 1; fontsel_info->properties[prop][0] = "*"; } /* Insert the font families into the main table, sorted by family and foundry (fonts with different foundries are placed in seaparate MozFontInfos. All fontnames in each family + foundry are placed into the fontnames array of lists. */ fontsel_info->nfonts = 0; for (i = 0; i < num_fonts; i++) { #ifdef FRV_DEBUG printf("Adding font %s\n", xfontnames[i]); #endif if (moz_xlfd_font_name (xfontnames[i])) { moz_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]); } else { #ifdef FRV_DEBUG g_warning("Skipping invalid font: %s", xfontnames[i]); #endif } } /* Since many font names will be in the same MozFontInfo not all of the allocated MozFontInfo table will be used, so we will now reallocate it with the real size. */ fontsel_info->font_info = g_realloc(fontsel_info->font_info, sizeof(MozFontInfo) * fontsel_info->nfonts); /* Now we work out which choices of weight/slant etc. are valid for each font. */ fontsel_info->nstyles = 0; current_style = fontsel_info->font_styles; for (i = 0; i < fontsel_info->nfonts; i++) { font = &fontsel_info->font_info[i]; /* Use the next free position in the styles array. */ font->style_index = fontsel_info->nstyles; /* Now step through each of the fontnames with this family, and create a style for each fontname. Each style contains the index into the weights/slants etc. arrays, and a number of pixel/point sizes. */ style = 0; temp_list = fontnames[i]; while (temp_list) { fontname = temp_list->data; temp_list = temp_list->next; for (prop = 0; prop < NUM_STYLE_PROPERTIES; prop++) { current_style->properties[prop] = moz_insert_field (fontname, prop); } current_style->pixel_sizes_index = npixel_sizes; current_style->npixel_sizes = 0; current_style->point_sizes_index = npoint_sizes; current_style->npoint_sizes = 0; current_style->flags = 0; field = moz_get_xlfd_field (fontname, XLFD_PIXELS, field_buffer); pixels = atoi(field); field = moz_get_xlfd_field (fontname, XLFD_POINTS, field_buffer); points = atoi(field); field = moz_get_xlfd_field (fontname, XLFD_RESOLUTION_X, field_buffer); res_x = atoi(field); field = moz_get_xlfd_field (fontname, XLFD_RESOLUTION_Y, field_buffer); res_y = atoi(field); if (pixels == 0 && points == 0) { if (res_x == 0 && res_y == 0) flags = SCALABLE_FONT; else { flags = SCALABLE_BITMAP_FONT; fontsel_info->scaled_bitmaps_available = TRUE; } } else flags = BITMAP_FONT; /* Now we check to make sure that the style is unique. If it isn't we forget it. */ prev_style = fontsel_info->font_styles + font->style_index; matched_style = FALSE; while (prev_style < current_style) { matched_style = TRUE; for (prop = 0; prop < NUM_STYLE_PROPERTIES; prop++) { if (prev_style->properties[prop] != current_style->properties[prop]) { matched_style = FALSE; break; } } if (matched_style) break; prev_style++; } /* If we matched an existing style, we need to add the pixels & point sizes to the style. If not, we insert the pixel & point sizes into our new style. Note that we don't add sizes for scalable fonts. */ if (matched_style) { prev_style->flags |= flags; if (flags == BITMAP_FONT) { pixel_sizes = fontsel_info->pixel_sizes + prev_style->pixel_sizes_index; found_size = FALSE; for (size = 0; size < prev_style->npixel_sizes; size++) { if (pixels == *pixel_sizes) { found_size = TRUE; break; } else if (pixels < *pixel_sizes) break; pixel_sizes++; } /* We need to move all the following pixel sizes up, and also update the indexes of any following styles. */ if (!found_size) { for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes; tmp_sizes > pixel_sizes; tmp_sizes--) *tmp_sizes = *(tmp_sizes - 1); *pixel_sizes = pixels; npixel_sizes++; prev_style->npixel_sizes++; tmp_style = prev_style + 1; while (tmp_style < current_style) { tmp_style->pixel_sizes_index++; tmp_style++; } } point_sizes = fontsel_info->point_sizes + prev_style->point_sizes_index; found_size = FALSE; for (size = 0; size < prev_style->npoint_sizes; size++) { if (points == *point_sizes) { found_size = TRUE; break; } else if (points < *point_sizes) break; point_sizes++; } /* We need to move all the following point sizes up, and also update the indexes of any following styles. */ if (!found_size) { for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes; tmp_sizes > point_sizes; tmp_sizes--) *tmp_sizes = *(tmp_sizes - 1); *point_sizes = points; npoint_sizes++; prev_style->npoint_sizes++; tmp_style = prev_style + 1; while (tmp_style < current_style) { tmp_style->point_sizes_index++; tmp_style++; } } } } else { current_style->flags = flags; if (flags == BITMAP_FONT) { fontsel_info->pixel_sizes[npixel_sizes++] = pixels; current_style->npixel_sizes = 1; fontsel_info->point_sizes[npoint_sizes++] = points; current_style->npoint_sizes = 1; } style++; fontsel_info->nstyles++; current_style++; } } g_slist_free(fontnames[i]); /* Set nstyles to the real value, minus duplicated fontnames. Note that we aren't using all the allocated memory if fontnames are duplicated. */ font->nstyles = style; } /* Since some repeated styles may be skipped we won't have used all the allocated space, so we will now reallocate it with the real size. */ fontsel_info->font_styles = g_realloc(fontsel_info->font_styles, sizeof(FontStyle) * fontsel_info->nstyles); fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes, sizeof(guint16) * npixel_sizes); fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes, sizeof(guint16) * npoint_sizes); g_free(fontnames); XFreeFontNames (xfontnames); /* Debugging Output */ /* This outputs all MozFontInfos. */ #ifdef FONTSEL_DEBUG g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n"); for (i = 0; i < fontsel_info->nfonts; i++) { MozFontInfo *font = &fontsel_info->font_info[i]; FontStyle *styles = fontsel_info->font_styles + font->style_index; for (style = 0; style < font->nstyles; style++) { g_message("%5i %-16.16s ", i, font->family); for (prop = 0; prop < NUM_STYLE_PROPERTIES; prop++) g_message("%-9.9s ", fontsel_info->properties[prop][styles->properties[prop]]); g_message("\n "); if (styles->flags & BITMAP_FONT) g_message("Bitmapped font "); if (styles->flags & SCALABLE_FONT) g_message("Scalable font "); if (styles->flags & SCALABLE_BITMAP_FONT) g_message("Scalable-Bitmapped font "); g_message("\n"); if (styles->npixel_sizes) { g_message(" Pixel sizes: "); tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index; for (size = 0; size < styles->npixel_sizes; size++) g_message("%i ", *tmp_sizes++); g_message("\n"); } if (styles->npoint_sizes) { g_message(" Point sizes: "); tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index; for (size = 0; size < styles->npoint_sizes; size++) g_message("%i ", *tmp_sizes++); g_message("\n"); } g_message("\n"); styles++; } } /* This outputs all available properties. */ for (prop = 0; prop < NUM_FONT_PROPERTIES; prop++) { g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]); for (i = 0; i < fontsel_info->nproperties[prop]; i++) g_message(" %s\n", fontsel_info->properties[prop][i]); } #endif } /************************************************************************ * The field parsing and manipulation routines *********************************************************************** /* This checks that the specified field of the given fontname is in the appropriate properties array. If not it is added. Thus eventually we get arrays of all possible weights/slants etc. It returns the array index. */ static gint moz_insert_field (gchar *fontname, gint prop) { gchar field_buffer[XLFD_MAX_FIELD_LEN]; gchar *field; guint16 index; field = moz_get_xlfd_field (fontname, xlfd_index[prop], field_buffer); if (!field) return 0; /* If the field is already in the array just return its index. */ for (index = 0; index < fontsel_info->nproperties[prop]; index++) if (!strcmp(field, fontsel_info->properties[prop][index])) return index; /* Make sure we have enough space to add the field. */ if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop]) { fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT; fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop], sizeof(gchar*) * fontsel_info->space_allocated[prop]); } /* Add the new field. */ index = fontsel_info->nproperties[prop]; fontsel_info->properties[prop][index] = g_strdup(field); fontsel_info->nproperties[prop]++; return index; } /* This inserts the given fontname into the FontInfo table. If a FontInfo already exists with the same family and foundry, then the fontname is added to the FontInfos list of fontnames, else a new FontInfo is created and inserted in alphabetical order in the table. */ static void moz_insert_font (GSList *fontnames[], gint *ntable, gchar *fontname) { MozFontInfo *table; MozFontInfo temp_info; GSList *temp_fontname; gchar *family; gboolean family_exists = FALSE; gint foundry; gint lower, upper; gint middle, cmp; gchar family_buffer[XLFD_MAX_FIELD_LEN]; table = fontsel_info->font_info; /* insert a fontname into a table */ family = moz_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer); if (!family) return; foundry = moz_insert_field (fontname, FOUNDRY); lower = 0; if (*ntable > 0) { /* Do a binary search to determine if we have already encountered * a font with this family & foundry. */ upper = *ntable; while (lower < upper) { middle = (lower + upper) >> 1; cmp = strcmp (family, table[middle].family); /* If the family matches we sort by the foundry. */ if (cmp == 0) { family_exists = TRUE; family = table[middle].family; cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry], fontsel_info->properties[FOUNDRY][table[middle].foundry]); } if (cmp == 0) { fontnames[middle] = g_slist_prepend (fontnames[middle], fontname); return; } else if (cmp < 0) upper = middle; else lower = middle+1; } } /* Add another entry to the table for this new font family */ temp_info.family = family_exists ? family : g_strdup(family); temp_info.foundry = foundry; temp_fontname = g_slist_prepend (NULL, fontname); (*ntable)++; /* Quickly insert the entry into the table in sorted order * using a modification of insertion sort and the knowledge * that the entries proper position in the table was determined * above in the binary search and is contained in the "lower" * variable. */ if (*ntable > 1) { upper = *ntable - 1; while (lower != upper) { table[upper] = table[upper-1]; fontnames[upper] = fontnames[upper-1]; upper--; } } table[lower] = temp_info; fontnames[lower] = temp_fontname; } /***************************************************************************** * These functions all deal with X Logical Font Description (XLFD) fontnames. * See the freely available documentation about this. *****************************************************************************/ /* * Returns TRUE if the fontname is a valid XLFD. * (It just checks if the number of dashes is 14, and that each * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it * makes it easier for me). */ static gboolean moz_xlfd_font_name (const gchar *fontname) { gint i = 0; gint field_len = 0; while (*fontname) { if (*fontname++ == '-') { if (field_len > XLFD_MAX_FIELD_LEN) return FALSE; field_len = 0; i++; } else field_len++; } return (i == 14) ? TRUE : FALSE; } /* * This fills the buffer with the specified field from the X Logical Font * Description name, and returns it. If fontname is NULL or the field is * longer than XFLD_MAX_FIELD_LEN it returns NULL. * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'. */ static gchar* moz_get_xlfd_field (const gchar *fontname, FontField field_num, gchar *buffer) { const gchar *t1, *t2; gint countdown, len, num_dashes; if (!fontname) return NULL; /* we assume this is a valid fontname...that is, it has 14 fields */ countdown = field_num; t1 = fontname; while (*t1 && (countdown >= 0)) if (*t1++ == '-') countdown--; num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1; for (t2 = t1; *t2; t2++) { if (*t2 == '-' && --num_dashes == 0) break; } if (t1 != t2) { /* Check we don't overflow the buffer */ len = (long) t2 - (long) t1; if (len > XLFD_MAX_FIELD_LEN - 1) return NULL; strncpy (buffer, t1, len); buffer[len] = 0; } else strcpy(buffer, "(nil)"); return buffer; } /* * This returns a X Logical Font Description font name, given all the pieces. * Note: this retval must be freed by the caller. */ static gchar * moz_create_xlfd (gint size, MozFontMetric metric, gchar *foundry, gchar *family, gchar *weight, gchar *slant, gchar *set_width, gchar *spacing, gchar *charset) { gchar buffer[16]; gchar *pixel_size = "*", *point_size = "*", *fontname; gint length; if (size <= 0) return NULL; sprintf (buffer, "%d", (int) size); if (metric == METRIC_PIXEL) pixel_size = buffer; else point_size = buffer; /* Note: be careful here - don't overrun the allocated memory. */ length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant) + strlen(set_width) + strlen(pixel_size) + strlen(point_size) + strlen(spacing) + strlen(charset) + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3 + 1 /* for the terminating '\0'. */; fontname = g_new(gchar, length); /* **NOTE**: If you change this string please change length above! */ sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s", foundry, family, weight, slant, set_width, pixel_size, point_size, spacing, charset); return fontname; } /* Returns the Gdkfont matching the description * Possible bug: Foundry info is not token into * account! First font that matches the family * name is taken. Feel free to fix this */ GdkFont *moz_get_font_with_family(char *fam, int pts, char *wgt, gboolean ita) { MozFontInfo *table; MozFontInfo *font; FontStyle *styles; gint tsize; gint middle, upper, lower; gint style; gint weight_index, slant_index, width_index, spacing_index, charset_index; gchar *slant; gchar *set_width; gchar *spacing; gchar *charset; gchar *weight; gint index=0; gint cmp; /* initialize fontsel_info if necessary */ /* perhaps needs to go into main routine */ if (!fontsel_info) { moz_font_init(); } tsize = fontsel_info->nfonts; table = fontsel_info->font_info; /* die a horible death if tsize == 0 */ /*XP_ASSERT(tsize > 0);*/ /* do a binary search for the family */ /* I am ignoring foundry issues here */ lower = 0; upper = tsize; middle; while (lower < upper) { middle = (lower + upper) >> 1; cmp = strcmp (fam, table[middle].family); if (cmp < 0 ) { upper = middle; } else if (cmp > 0) { lower = middle+1; } else { /* we have have a hit! */ index=middle; break; } } /* if we haven't found our font, return NULL */ /* check that index is 0 to be sure */ if ( (lower >= upper) && (index == 0) ) { return NULL; } font = &table[index]; /* Find the best match (seperate routine perhaps?) */ styles= &fontsel_info->font_styles[font->style_index]; for (style=0; style < font->nstyles; style++) { /* grab the indices */ weight_index = styles[style].properties[WEIGHT]; slant_index = styles[style].properties[SLANT]; width_index = styles[style].properties[SET_WIDTH]; spacing_index = styles[style].properties[SPACING]; charset_index = styles[style].properties[CHARSET]; weight = fontsel_info->properties[WEIGHT] [weight_index]; slant = fontsel_info->properties[SLANT] [slant_index]; set_width = fontsel_info->properties[SET_WIDTH][width_index]; spacing = fontsel_info->properties[SPACING] [spacing_index]; charset = fontsel_info->properties[CHARSET] [charset_index]; if (strcmp(set_width, "nil") == 0) set_width=""; if (strcmp(spacing, "nil") == 0 ) set_width=""; if (strcmp(charset, "nil") == 0 ) charset=""; /* find a match, grab the font and run */ if (strcmp(weight, wgt) == 0) { if (ita) { if (g_strcasecmp(slant, "i") == 0) { return gdk_font_load ( moz_create_xlfd(pts, METRIC_PIXEL, fontsel_info->properties[FOUNDRY][font->foundry], fam, wgt, slant, set_width, spacing, charset)); } } else if (g_strcasecmp(slant, "r") == 0) { return gdk_font_load ( moz_create_xlfd(pts, METRIC_PIXEL, fontsel_info->properties[FOUNDRY][font->foundry], fam, wgt, slant, set_width, spacing, charset)); } } } } typedef enum { WEIGHT_LIGHT = 25, WEIGHT_MEDIUM=50, WEIGHT_BOLD = 75 } WeightType; GdkFont * moz_get_font(LO_TextAttr *text_attr) { GdkFont *result; char fam[100]; char *family_name; char *weight; int pts, wgt; gboolean ita; int size3 = 12; int length, index; if (text_attr->FE_Data) { return (GdkFont*)(text_attr->FE_Data); } if (!text_attr->font_face) { /* where can I retrieve the preferneces default font???? */ strcpy(fam, (text_attr->fontmask & LO_FONT_FIXED) ? "courier" : "times"); } else { strcpy(fam, text_attr->font_face); /* to make sure we always get a font returning... */ if (strlen(fam) < 90) strcat(fam, ",times"); } wgt=text_attr->font_weight; /* this is a bit hacky... */ if (!wgt) { wgt = (text_attr->fontmask & LO_FONT_BOLD) ? WEIGHT_BOLD : WEIGHT_MEDIUM; } if (wgt <= WEIGHT_LIGHT) { weight = "light"; } else if (wgt > WEIGHT_LIGHT && wgt < WEIGHT_BOLD) { weight = "medium"; } else { weight = "bold"; } ita = (text_attr->fontmask & LO_FONT_ITALIC) ? TRUE : FALSE; /* I don't understand this formula, and stole is straight from * qtfe. Corrections welcome */ pts = (text_attr->point_size); if ( pts <= 0) { switch ( text_attr->size ) { case 1: pts = 8; break; case 2: pts = 10; break; case 3: pts = 12; break; case 4: pts = 14; break; case 5: pts = 18; break; case 6: pts = 24; break; default: pts = (text_attr->size-6)*4+24; } pts = pts * size3 / 12; } length = strlen(fam); family_name = NameFromList(fam); while (family_name) { result = moz_get_font_with_family(family_name, pts, weight, ita); if (result) break; /* wipe out the name, and go on to the next */ index = 0; while (fam[index] != '\0') { fam[index] = ' '; index++; } if (index != length) fam[index] = ' '; family_name = NameFromList(fam); } XP_ASSERT(result); text_attr->FE_Data = result; return result; } void moz_font_release_text_attribute(LO_TextAttr *attr) { g_free( (GdkFont*)attr->FE_Data); } /* Adapted from XFE, but returns */ static char * NameFromList(char *namelist) { static char * list; static int next; static int len; int start; int end; char final = '\0'; if (namelist) { list = namelist; len = strlen(namelist); next = 0; } start = next; if (! list || list[start] == '\0') return (char *) NULL; /* skip over leading whitespace and commas to find the start of the name */ while (list[start] != '\0' && (list[start] == ',' || isspace(list[start]))) start++; /* find the end of the name */ next = start; while(list[next] != '\0' && list[next] != ',') { if (list[next] == '"' || list[next] == '\'') { final = list[next]; /* find the matching quote */ next++; while (list[next] != '\0' && list[next] != final) next++; /* if list[next] is null, there was no matching quote, so bail */ if (list[next] == '\0') break; } next++; } end = next - 1; if (list[next] != '\0' && next < len) next++; /* strip off trailing whitespace */ while (end >= start && isspace(list[end])) end--; /* if it's quoted, strip off the quotes */ if ((list[start] == '"' || list[start] == '\'') && list[end] == list[start]) { start++; end--; } end++; list[end] = '\0'; return &(list[start]); }