+/* Interface to fontset handler. */
+
+/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
+struct font_info *
+x_get_font_info (f, font_idx)
+ FRAME_PTR f;
+ int font_idx;
+{
+ return (FRAME_X_FONT_TABLE (f) + font_idx);
+}
+
+
+/* Return a list of names of available fonts matching PATTERN on frame
+ F. If SIZE is not 0, it is the size (maximum bound width) of fonts
+ to be listed. Frame F NULL means we have not yet created any
+ frame on X, and consult the first display in x_display_list.
+ MAXNAMES sets a limit on how many fonts to match. */
+
+Lisp_Object
+x_list_fonts (f, pattern, size, maxnames)
+ FRAME_PTR f;
+ Lisp_Object pattern;
+ int size;
+ int maxnames;
+{
+ Lisp_Object list = Qnil, patterns, newlist = Qnil, key, tem, second_best;
+ Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
+
+ patterns = Fassoc (pattern, Valternate_fontname_alist);
+ if (NILP (patterns))
+ patterns = Fcons (pattern, Qnil);
+
+ /* We try at least 10 fonts because X server will return auto-scaled
+ fonts at the head. */
+ if (maxnames < 10) maxnames = 10;
+
+ for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
+ {
+ int num_fonts;
+ char **names;
+
+ pattern = XCONS (patterns)->car;
+ /* See if we cached the result for this particular query.
+ The cache is an alist of the form:
+ (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
+ */
+ if (f && (tem = XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr,
+ key = Fcons (pattern, make_number (maxnames)),
+ !NILP (list = Fassoc (key, tem))))
+ {
+ list = Fcdr_safe (list);
+ /* We have a cashed list. Don't have to get the list again. */
+ goto label_cached;
+ }
+
+ /* At first, put PATTERN in the cache. */
+ BLOCK_INPUT;
+ names = XListFonts (dpy, XSTRING (pattern)->data, maxnames, &num_fonts);
+ UNBLOCK_INPUT;
+
+ if (names)
+ {
+ int i;
+
+ /* Make a list of all the fonts we got back.
+ Store that in the font cache for the display. */
+ for (i = 0; i < num_fonts; i++)
+ {
+ char *p = names[i];
+ int average_width = -1, dashes = 0, width = 0;
+
+ /* Count the number of dashes in NAMES[I]. If there are
+ 14 dashes, and the field value following 12th dash
+ (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
+ is usually too ugly to be used for editing. Let's
+ ignore it. */
+ while (*p)
+ if (*p++ == '-')
+ {
+ dashes++;
+ if (dashes == 7) /* PIXEL_SIZE field */
+ width = atoi (p);
+ else if (dashes == 12) /* AVERAGE_WIDTH field */
+ average_width = atoi (p);
+ }
+ if (dashes < 14 || average_width != 0)
+ {
+ tem = build_string (names[i]);
+ if (NILP (Fassoc (tem, list)))
+ {
+ if (STRINGP (Vx_pixel_size_width_font_regexp)
+ && ((fast_c_string_match_ignore_case
+ (Vx_pixel_size_width_font_regexp, names[i]))
+ >= 0))
+ /* We can set the value of PIXEL_SIZE to the
+ width of this font. */
+ list = Fcons (Fcons (tem, make_number (width)), list);
+ else
+ /* For the moment, width is not known. */
+ list = Fcons (Fcons (tem, Qnil), list);
+ }
+ }
+ }
+ XFreeFontNames (names);
+ }
+
+ /* Now store the result in the cache. */
+ if (f != NULL)
+ XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr
+ = Fcons (Fcons (key, list),
+ XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
+
+ label_cached:
+ if (NILP (list)) continue; /* Try the remaining alternatives. */
+
+ newlist = second_best = Qnil;
+ /* Make a list of the fonts that have the right width. */
+ for (; CONSP (list); list = XCONS (list)->cdr)
+ {
+ int found_size;
+
+ tem = XCONS (list)->car;
+
+ if (!CONSP (tem) || NILP (XCONS (tem)->car))
+ continue;
+ if (!size)
+ {
+ newlist = Fcons (XCONS (tem)->car, newlist);
+ continue;
+ }
+
+ if (!INTEGERP (XCONS (tem)->cdr))
+ {
+ /* Since we have not yet known the size of this font, we
+ must try slow function call XLoadQueryFont. */
+ XFontStruct *thisinfo;
+
+ BLOCK_INPUT;
+ thisinfo = XLoadQueryFont (dpy,
+ XSTRING (XCONS (tem)->car)->data);
+ UNBLOCK_INPUT;
+
+ if (thisinfo)
+ {
+ XCONS (tem)->cdr
+ = (thisinfo->min_bounds.width == 0
+ ? make_number (0)
+ : make_number (thisinfo->max_bounds.width));
+ XFreeFont (dpy, thisinfo);
+ }
+ else
+ /* For unknown reason, the previous call of XListFont had
+ retruned a font which can't be opened. Record the size
+ as 0 not to try to open it again. */
+ XCONS (tem)->cdr = make_number (0);
+ }
+
+ found_size = XINT (XCONS (tem)->cdr);
+ if (found_size == size)
+ newlist = Fcons (XCONS (tem)->car, newlist);
+ else if (found_size > 0)
+ {
+ if (NILP (second_best))
+ second_best = tem;
+ else if (found_size < size)
+ {
+ if (XINT (XCONS (second_best)->cdr) > size
+ || XINT (XCONS (second_best)->cdr) < found_size)
+ second_best = tem;
+ }
+ else
+ {
+ if (XINT (XCONS (second_best)->cdr) > size
+ && XINT (XCONS (second_best)->cdr) > found_size)
+ second_best = tem;
+ }
+ }
+ }
+ if (!NILP (newlist))
+ break;
+ else if (!NILP (second_best))
+ {
+ newlist = Fcons (XCONS (second_best)->car, Qnil);
+ break;
+ }
+ }
+
+ return newlist;
+}
+
+/* Load font named FONTNAME of the size SIZE for frame F, and return a
+ pointer to the structure font_info while allocating it dynamically.
+ If SIZE is 0, load any size of font.
+ If loading is failed, return NULL. */
+
+struct font_info *
+x_load_font (f, fontname, size)
+ struct frame *f;
+ register char *fontname;
+ int size;
+{
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Lisp_Object font_names;
+
+ /* Get a list of all the fonts that match this name. Once we
+ have a list of matching fonts, we compare them against the fonts
+ we already have by comparing names. */
+ font_names = x_list_fonts (f, build_string (fontname), size, 256);
+
+ if (!NILP (font_names))
+ {
+ Lisp_Object tail;
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
+ if (!strcmp (dpyinfo->font_table[i].name,
+ XSTRING (XCONS (tail)->car)->data)
+ || !strcmp (dpyinfo->font_table[i].full_name,
+ XSTRING (XCONS (tail)->car)->data))
+ return (dpyinfo->font_table + i);
+ }
+
+ /* Load the font and add it to the table. */
+ {
+ char *full_name;
+ XFontStruct *font;
+ struct font_info *fontp;
+ unsigned long value;
+
+ /* If we have found fonts by x_list_font, load one of them. If
+ not, we still try to load a font by the name given as FONTNAME
+ because XListFonts (called in x_list_font) of some X server has
+ a bug of not finding a font even if the font surely exists and
+ is loadable by XLoadQueryFont. */
+ if (!NILP (font_names))
+ fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
+
+ BLOCK_INPUT;
+ font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
+ UNBLOCK_INPUT;
+ if (!font)
+ return NULL;
+
+ /* Do we need to create the table? */
+ if (dpyinfo->font_table_size == 0)
+ {
+ dpyinfo->font_table_size = 16;
+ dpyinfo->font_table
+ = (struct font_info *) xmalloc (dpyinfo->font_table_size
+ * sizeof (struct font_info));
+ }
+ /* Do we need to grow the table? */
+ else if (dpyinfo->n_fonts
+ >= dpyinfo->font_table_size)
+ {
+ dpyinfo->font_table_size *= 2;
+ dpyinfo->font_table
+ = (struct font_info *) xrealloc (dpyinfo->font_table,
+ (dpyinfo->font_table_size
+ * sizeof (struct font_info)));
+ }
+
+ fontp = dpyinfo->font_table + dpyinfo->n_fonts;
+
+ /* Now fill in the slots of *FONTP. */
+ BLOCK_INPUT;
+ fontp->font = font;
+ fontp->font_idx = dpyinfo->n_fonts;
+ fontp->name = (char *) xmalloc (strlen (fontname) + 1);
+ bcopy (fontname, fontp->name, strlen (fontname) + 1);
+
+ /* Try to get the full name of FONT. Put it in FULL_NAME. */
+ full_name = 0;
+ if (XGetFontProperty (font, XA_FONT, &value))
+ {
+ char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
+ char *p = name;
+ int dashes = 0;
+
+ /* Count the number of dashes in the "full name".
+ If it is too few, this isn't really the font's full name,
+ so don't use it.
+ In X11R4, the fonts did not come with their canonical names
+ stored in them. */
+ while (*p)
+ {
+ if (*p == '-')
+ dashes++;
+ p++;
+ }
+
+ if (dashes >= 13)
+ {
+ full_name = (char *) xmalloc (p - name + 1);
+ bcopy (name, full_name, p - name + 1);
+ }
+
+ XFree (name);
+ }
+
+ if (full_name != 0)
+ fontp->full_name = full_name;
+ else
+ fontp->full_name = fontp->name;
+
+ fontp->size = font->max_bounds.width;
+ fontp->height = font->max_bounds.ascent + font->max_bounds.descent;
+
+ if (NILP (font_names))
+ {
+ /* We come here because of a bug of XListFonts mentioned at
+ the head of this block. Let's store this information in
+ the cache for x_list_fonts. */
+ Lisp_Object lispy_name = build_string (fontname);
+ Lisp_Object lispy_full_name = build_string (fontp->full_name);
+
+ XCONS (dpyinfo->name_list_element)->cdr
+ = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
+ Fcons (Fcons (lispy_full_name,
+ make_number (fontp->size)),
+ Qnil)),
+ XCONS (dpyinfo->name_list_element)->cdr);
+ if (full_name)
+ XCONS (dpyinfo->name_list_element)->cdr
+ = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
+ Fcons (Fcons (lispy_full_name,
+ make_number (fontp->size)),
+ Qnil)),
+ XCONS (dpyinfo->name_list_element)->cdr);
+ }
+
+ /* The slot `encoding' specifies how to map a character
+ code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
+ the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
+ the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
+ 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
+ 2:0xA020..0xFF7F). For the moment, we don't know which charset
+ uses this font. So, we set informatoin in fontp->encoding[1]
+ which is never used by any charset. If mapping can't be
+ decided, set FONT_ENCODING_NOT_DECIDED. */
+ fontp->encoding[1]
+ = (font->max_byte1 == 0
+ /* 1-byte font */
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x20..0x7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
+ : 1) /* 0xA0..0xFF */
+ /* 2-byte font */
+ : (font->min_byte1 < 0x80
+ ? (font->max_byte1 < 0x80
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x2020..0x7F7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
+ : 3) /* 0x20A0..0x7FFF */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
+ : (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 2 /* 0xA020..0xFF7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
+ : 1))); /* 0xA0A0..0xFFFF */
+
+ fontp->baseline_offset
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
+ ? (long) value : 0);
+ fontp->relative_compose
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
+ ? (long) value : 0);
+ fontp->default_ascent
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
+ ? (long) value : 0);
+
+ UNBLOCK_INPUT;
+ dpyinfo->n_fonts++;
+
+ return fontp;
+ }
+}
+
+/* Return a pointer to struct font_info of a font named FONTNAME for frame F.
+ If no such font is loaded, return NULL. */
+struct font_info *
+x_query_font (f, fontname)
+ struct frame *f;
+ register char *fontname;
+{
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (!strcmp (dpyinfo->font_table[i].name, fontname)
+ || !strcmp (dpyinfo->font_table[i].full_name, fontname))
+ return (dpyinfo->font_table + i);
+ return NULL;
+}
+
+\f