changeset 4758:75975fd0b7fc

Implement more of the fontconfig API. Improve implementation, avoiding nonsyntactic macros and compiler warnings. Clean up some documentation. Guard against freeing NULL pointers returned from fonconfig.
author Stephen J. Turnbull <stephen@xemacs.org>
date Wed, 18 Nov 2009 22:44:28 +0900
parents a23ac8f90a49
children aa5ed11f473b dec62ca5a899
files src/ChangeLog src/font-mgr.c src/font-mgr.h src/objects-xlike-inc.c
diffstat 4 files changed, 372 insertions(+), 232 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Wed Nov 18 15:25:00 2009 +0900
+++ b/src/ChangeLog	Wed Nov 18 22:44:28 2009 +0900
@@ -1,3 +1,39 @@
+2009-11-18  Stephen J. Turnbull  <stephen@xemacs.org>
+
+	Assorted cleanups.
+
+	* font-mgr.h (CHECKING_LANG): Remove redundant conversion.
+
+	* font-mgr.c: Update copyright notice and author headers.
+	Reorder some functions.
+
+	* objects-xlike-inc.c (xft_find_charset_font): Check for freeing NULL.
+
+	Implement more of fontconfig API.
+
+	* font-mgr.c: (Ffc_default_substitute):
+	(Ffc_config_substitute):
+	(Ffc_font_render_prepare):
+	New functions.
+	(Ffc_font_match):
+	Gets optional argument CONFIG.
+	(Ffc_config_destroy):
+	Fix a typo.
+
+	Reimplement FCSTRLIST_TO_LISP_USING as a function.
+
+	(FCSTRLIST_TO_LISP_USING): Removed.
+	(fcstrlist_to_lisp_using): New function.
+	(Ffc_config_get_config_dirs):
+	(Ffc_config_get_font_dirs):
+	(Ffc_config_get_config_files):
+	Replace FCSTRLIST_TO_LISP_USING with fcstrlist_to_lisp_using.
+
+	Comment cleanups.
+
+	* objects-xlike-inc.c (charset_reporter): Document RFC 3066.
+	(xft_find_charset_font): Remove obsolete comment.
+
 2009-10-18  Stephen J. Turnbull  <stephen@xemacs.org>
 
 	* font-mgr.h (PRINT_XFT_PATTERN):
--- a/src/font-mgr.c	Wed Nov 18 15:25:00 2009 +0900
+++ b/src/font-mgr.c	Wed Nov 18 22:44:28 2009 +0900
@@ -2,13 +2,13 @@
 
 Copyright (C) 2003 Eric Knauel and Matthias Neubauer
 Copyright (C) 2005 Eric Knauel
-Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+Copyright (C) 2004-2009 Free Software Foundation, Inc.
 
 Authors:	Eric Knauel <knauel@informatik.uni-tuebingen.de>
 		Matthias Neubauer <neubauer@informatik.uni-freiburg.de>
 		Stephen J. Turnbull <stephen@xemacs.org>
 Created:	27 Oct 2003
-Updated:	14 April 2007 by Stephen J. Turnbull
+Updated:	18 November 2009 by Stephen J. Turnbull
 
 This file is part of XEmacs.
 
@@ -74,6 +74,8 @@
 Lisp_Object Qfc_result_no_match; 	/* FcResultNoMatch */
 Lisp_Object Qfc_result_no_id;		/* FcResultNoId */
 Lisp_Object Qfc_internal_error;
+Lisp_Object Qfc_match_pattern;
+Lisp_Object Qfc_match_font;
 Lisp_Object Vxlfd_font_name_regexp;	/* #### Really needed? */
 Fixnum xft_version;
 Fixnum fc_version;
@@ -489,50 +491,57 @@
     }
 }
 
-DEFUN("fc-font-match", Ffc_font_match, 2, 2, 0, /*
-Return the font on DEVICE that most closely matches PATTERN.
+/* FcConfig handling functions. */
 
-DEVICE is an X11 device.
-PATTERN is a fontconfig pattern object.
-Returns a fontconfig pattern object representing the closest match to the
-given pattern, or an error code.  Possible error codes are
-`fc-result-no-match' and `fc-result-no-id'. */
-      (device, pattern))
-{
-  FcResult res;
-  struct fc_pattern *res_fcpat;
+/* We obviously need to be careful about garbage collecting the current
+   FcConfig.  I infer from the documentation of FcConfigDestroy that that
+   is the only reference maintained by fontconfig.
+   So we keep track of our own references on a weak list, and only cons a
+   new object if we don't already have a reference to it there. */
+
+enum DestroyFontsetP { DestroyNo = 0, DestroyYes = 1 };
 
-  CHECK_FCPATTERN(pattern);
-  if (NILP(device))
-    return Qnil;
-  CHECK_X_DEVICE(device);
-  if (!DEVICE_LIVE_P(XDEVICE(device)))
-    return Qnil;
+static Lisp_Object
+fc_config_create_using (FcConfig * (*create_function) ())
+{
+  FcConfig *fc = (*create_function) ();
+  Lisp_Object configs = XWEAK_LIST_LIST (Vfc_config_weak_list);
 
-  res_fcpat = ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
+  /* Linear search: fc_configs are not going to multiply like conses. */
   {
-    FcPattern *p = XFCPATTERN_PTR(pattern);
-    FcConfig *fcc = FcConfigGetCurrent ();
-
-    FcConfigSubstitute (fcc, p, FcMatchPattern);
-    FcDefaultSubstitute (p);
-    res_fcpat->fcpatPtr = FcFontMatch (fcc, p, &res);
+    LIST_LOOP_2 (cfg, configs)
+      if (fc == XFCCONFIG_PTR (cfg))
+	return cfg;
   }
 
-  if (res_fcpat->fcpatPtr == NULL)
-    switch (res) {
-    case FcResultNoMatch:
-      return Qfc_result_no_match;
-    case FcResultNoId:
-      return Qfc_result_no_id;
-    default:
-      return Qfc_internal_error;
-    }
-  else
-    return wrap_fcpattern(res_fcpat);
+  {
+    fc_config *fccfg =
+      ALLOC_LCRECORD_TYPE (struct fc_config, &lrecord_fc_config);
+    fccfg->fccfgPtr = fc;
+    configs = Fcons (wrap_fcconfig (fccfg), configs);
+    XWEAK_LIST_LIST (Vfc_config_weak_list) = configs;
+    return wrap_fcconfig (fccfg);
+  }
 }
 
-enum DestroyFontsetP { DestroyNo = 0, DestroyYes = 1 };
+static Lisp_Object
+fc_strlist_to_lisp_using (FcStrList * (*getter) (FcConfig *),
+			  Lisp_Object config)
+{
+  FcChar8 *thing;
+  Lisp_Object value = Qnil;
+  FcStrList *thing_list;
+  
+  CHECK_FCCONFIG (config);     
+  thing_list = (*getter) (XFCCONFIG_PTR(config));
+  /* Yes, we need to do this check -- sheesh, Keith! */
+  if (!thing_list)
+    return Qnil;
+  while ((thing = FcStrListNext (thing_list)))
+    value = Fcons (build_fcapi_string (thing), value);
+  FcStrListDone (thing_list);
+  return value;
+}
 
 static Lisp_Object
 fontset_to_list (FcFontSet *fontset, enum DestroyFontsetP destroyp)
@@ -557,148 +566,6 @@
   return fontlist;
 }
 
-/* #### fix this name to correspond to Ben's new nomenclature */
-DEFUN("fc-list-fonts-pattern-objects", Ffc_list_fonts_pattern_objects,
-      3, 3, 0, /*
-Return a list of fonts on DEVICE that match PATTERN for PROPERTIES.
-Each font is represented by a fontconfig pattern object.
-
-DEVICE is an X11 device.
-PATTERN is a fontconfig pattern to be matched.
-PROPERTIES is a list of property names (strings) that should match.
-
-#### DEVICE is unused, ignored, and may be removed if it's not needed to
-match other font-listing APIs. */
-      (UNUSED (device), pattern, properties))
-{
-  FcObjectSet *os;
-  FcFontSet *fontset;
-
-  CHECK_FCPATTERN (pattern);
-  CHECK_LIST (properties);
-
-  os = FcObjectSetCreate ();
-  string_list_to_fcobjectset (properties, os);
-  /* #### why don't we need to do the "usual substitutions"? */
-  fontset = FcFontList (NULL, XFCPATTERN_PTR (pattern), os);
-  FcObjectSetDestroy (os);
-
-  return fontset_to_list (fontset, DestroyYes);
-
-}
-
-/* #### maybe this can/should be folded into fc-list-fonts-pattern-objects? */
-DEFUN("fc-font-sort", Ffc_font_sort, 2, 4, 0, /*
-Return a list of all fonts sorted by proximity to PATTERN.
-Each font is represented by a fontconfig pattern object.
-
-DEVICE is an X11 device.
-PATTERN is a fontconfig pattern to be matched.
-Optional argument TRIM, if non-nil, means to trim trailing fonts that do not
-contribute new characters to the union repertoire.
-
-#### Optional argument NOSUB, if non-nil, suppresses some of the usual
-property substitutions.  DON'T USE THIS in production code, it is intended
-for exploring behavior of fontconfig and will be removed when this code is
-stable.
-
-#### DEVICE is unused, ignored, and may be removed if it's not needed to
-match other font-listing APIs. */
-      (UNUSED (device), pattern, trim, nosub))
-{
-  CHECK_FCPATTERN (pattern);
-
-  {
-    FcConfig *fcc = FcConfigGetCurrent();
-    FcFontSet *fontset;
-    FcPattern *p = XFCPATTERN_PTR (pattern);
-    FcResult fcresult;
-
-    if (NILP(nosub))		/* #### temporary debug hack */
-      FcDefaultSubstitute (p);
-    FcConfigSubstitute (fcc, p, FcMatchPattern);
-    fontset = FcFontSort (fcc, p, !NILP(trim), NULL, &fcresult);
-
-    return fontset_to_list (fontset, DestroyYes);
-  }
-}
-
-#ifdef FONTCONFIG_EXPOSE_CONFIG
-
-/* Configuration routines --- for debugging
-   Don't depend on these routines being available in the future!
-
-   3.2.10 Initialization
-   ---------------------
-
-   An FcConfig object holds the internal representation of a configuration.
-   There is a default configuration which applications may use by passing
-   0 to any function using the data within an FcConfig.
-*/
-
-static void
-finalize_fc_config (void *header, int UNUSED (for_disksave))
-{
-  struct fc_config *p = (struct fc_config *) header;
-  if (p->fccfgPtr && p->fccfgPtr != FcConfigGetCurrent())
-    {
-      /* If we get here, all of *our* references are garbage (see comment on
-	 fc_config_create_using() for why), and the only reference that
-	 fontconfig keeps is the current FcConfig. */
-      FcConfigDestroy (p->fccfgPtr);
-    }
-  p->fccfgPtr = 0;
-}
-
-static void
-print_fc_config (Lisp_Object obj, Lisp_Object printcharfun,
-		 int UNUSED(escapeflag))
-{
-  struct fc_config *c = XFCCONFIG (obj);
-  if (print_readably)
-    printing_unreadable_object ("#<fc-config 0x%x>", c->header.uid);
-  write_fmt_string (printcharfun, "#<fc-config 0x%x>", c->header.uid);
-}
-
-static const struct memory_description fcconfig_description [] = {
-  /* #### nothing here, is this right?? */
-  { XD_END }
-};
-
-DEFINE_LRECORD_IMPLEMENTATION("fc-config", fc_config, 0,
-			      0, print_fc_config, finalize_fc_config, 0, 0,
-			      fcconfig_description,
-			      struct fc_config);
-
-/* We obviously need to be careful about garbage collecting the current
-   FcConfig.  I infer from the documentation of FcConfigDestroy that that
-   is the only reference maintained by fontconfig.
-   So we keep track of our own references on a weak list, and only cons a
-   new object if we don't already have a reference to it there. */
-
-static Lisp_Object
-fc_config_create_using (FcConfig * (*create_function) ())
-{
-  FcConfig *fc = (*create_function) ();
-  Lisp_Object configs = XWEAK_LIST_LIST (Vfc_config_weak_list);
-
-  /* Linear search: fc_configs are not going to multiply like conses. */
-  {
-    LIST_LOOP_2 (cfg, configs)
-      if (fc == XFCCONFIG_PTR (cfg))
-	return cfg;
-  }
-
-  {
-    fc_config *fccfg =
-      ALLOC_LCRECORD_TYPE (struct fc_config, &lrecord_fc_config);
-    fccfg->fccfgPtr = fc;
-    configs = Fcons (wrap_fcconfig (fccfg), configs);
-    XWEAK_LIST_LIST (Vfc_config_weak_list) = configs;
-    return wrap_fcconfig (fccfg);
-  }
-}
-
 DEFUN("fc-config-p", Ffc_config_p, 1, 1, 0, /*
 Returns t if OBJECT is of type fc-config, nil otherwise.
 */
@@ -727,18 +594,10 @@
       (config))
 {
   signal_error (Qunimplemented, "No user-servicable parts!",
-		intern ("fc-config-destroy");
+		intern ("fc-config-destroy"));
 }
 #endif
 
-DEFUN("fc-config-get-current", Ffc_config_get_current, 0, 0, 0, /*
- -- Function: FcConfig *FcConfigGetCurrent (void)
-     Returns the current default configuration. */
-      ())
-{
-  return fc_config_create_using (&FcConfigGetCurrent);
-}
-
 DEFUN("fc-config-up-to-date", Ffc_config_up_to_date, 1, 1, 0, /*
  -- Function: FcBool FcConfigUptoDate (FcConfig *config)
      Checks all of the files related to 'config' and returns whether the
@@ -764,23 +623,6 @@
   return Qnil;
 }
 
-/* Calls its argument on `config', which must be defined by the caller. */
-
-#define FCSTRLIST_TO_LISP_USING(source) do {			\
-  FcChar8 *thing;					\
-  FcStrList *thing_list;					\
-  Lisp_Object value = Qnil;				\
-  CHECK_FCCONFIG (config);				\
-  thing_list = source (XFCCONFIG_PTR(config));		\
-  /* Yes, we need to do this check -- sheesh, Keith! */	\
-  if (!thing_list)					\
-    return Qnil;					\
-  while ((thing = FcStrListNext (thing_list)))		\
-    value = Fcons (build_fcapi_string (thing), value);	\
-  FcStrListDone (thing_list);				\
-  return value;						\
-  } while (0)
-
 DEFUN("fc-config-get-config-dirs", Ffc_config_get_config_dirs, 1, 1, 0, /*
  -- Function: FcStrList *FcConfigGetConfigDirs (FcConfig *config)
      Returns the list of font directories specified in the
@@ -788,7 +630,7 @@
      subdirectories. */
       (config))
 {
-  FCSTRLIST_TO_LISP_USING (FcConfigGetConfigDirs);
+  return fc_strlist_to_lisp_using (&FcConfigGetConfigDirs, config);
 }
 
 DEFUN("fc-config-get-font-dirs", Ffc_config_get_font_dirs, 1, 1, 0, /*
@@ -798,7 +640,7 @@
      in the filesystem. */
       (config))
 {
-  FCSTRLIST_TO_LISP_USING (FcConfigGetFontDirs);
+  return fc_strlist_to_lisp_using (&FcConfigGetFontDirs, config);
 }
 
 DEFUN("fc-config-get-config-files", Ffc_config_get_config_files, 1, 1, 0, /*
@@ -808,11 +650,9 @@
      with FcConfigParse. */
       (config))
 {
- FCSTRLIST_TO_LISP_USING (FcConfigGetConfigFiles);
+ return fc_strlist_to_lisp_using (&FcConfigGetConfigFiles, config);
 }
 
-#undef FCSTRLIST_TO_LISP_USING
-
 DEFUN("fc-config-get-cache", Ffc_config_get_cache, 1, 1, 0, /*
  -- Function: char *FcConfigGetCache (FcConfig *config)
      Returns the name of the file used to store per-user font
@@ -1023,6 +863,270 @@
   return fc_config_create_using (&FcInitLoadConfigAndFonts);
 }
 
+DEFUN("fc-config-get-current", Ffc_config_get_current, 0, 0, 0, /*
+ -- Function: FcConfig *FcConfigGetCurrent (void)
+     Returns the current default configuration. */
+      ())
+{
+  return fc_config_create_using (&FcConfigGetCurrent);
+}
+
+/* Pattern manipulation functions. */
+
+DEFUN("fc-default-substitute", Ffc_default_substitute, 1, 1, 0, /*
+Adds defaults for certain attributes if not specified in PATTERN.
+FcPattern PATTERN is modified in-place, and nil is returned.
+* Patterns without a specified style or weight are set to Medium
+* Patterns without a specified style or slant are set to Roman
+* Patterns without a specified pixel size are given one computed from any
+  specified point size (default 12), dpi (default 75) and scale (default 1). */
+      (pattern))
+{
+  CHECK_FCPATTERN (pattern);
+  FcDefaultSubstitute (XFCPATTERN_PTR (pattern));
+  return Qnil;
+}
+
+/* -- Function: FcBool FcConfigSubstituteWithPat (FcConfig *config,
+          FcPattern *p, FcPattern *p_pat FcMatchKind kind)
+     OMITTED: use optional arguments in `fc-config-substitute'. */
+
+DEFUN("fc-config-substitute", Ffc_config_substitute, 1, 4, 0, /*
+Modifies PATTERN according to KIND and TESTPAT using operations from CONFIG.
+PATTERN is modified in-place.  Returns an undocumented Boolean value.
+If optional KIND is `fc-match-pattern', then those tagged as pattern operations
+are applied, else if KIND is `fc-match-font', those tagged as font operations
+are applied and TESTPAT is used for <test> elements with target=pattern.  KIND
+defaults to `fc-match-font'.
+If optional TESTPAT is nil, it is ignored.  Otherwise it must be an FcPattern.
+Optional CONFIG must be an FcConfig, defaulting to the current one.
+
+Note that this function actually corresponds to FcConfigSubstituteWithPat, and
+the argument order is changed to take advantage of Lisp optional arguments. */
+      (pattern, kind, testpat, config))
+{
+  FcMatchKind knd;
+
+  /* There ought to be a standard idiom for this.... */
+  if (NILP (kind)
+      || EQ (kind, Qfc_match_font)) {
+    knd = FcMatchFont;
+  }
+  else if (EQ (kind, Qfc_match_pattern)) {
+    knd = FcMatchPattern;
+  }
+  else {
+    Fsignal (Qwrong_type_argument,
+	     list2 (build_string ("need `fc-match-pattern' or `fc-match-font'"),
+		    kind));
+  }
+
+  /* Typecheck arguments */
+  CHECK_FCPATTERN (pattern);
+  if (!NILP (testpat)) CHECK_FCPATTERN (testpat);
+  if (!NILP (config))  CHECK_FCCONFIG (config);
+
+  return (FcConfigSubstituteWithPat
+	  (NILP (config) ? FcConfigGetCurrent () : XFCCONFIG_PTR (config),
+	   XFCPATTERN_PTR (pattern),
+	   NILP (testpat) ? NULL : XFCPATTERN_PTR (testpat),
+	   knd) == FcTrue)
+	 ? Qt : Qnil;
+}
+
+/* Pattern matching functions. */
+
+/* The following functions return fonts that match a certain pattern.
+   `FcFontRenderPrepare' and `FcFontMatch' always return a single best
+   match.  `FcFontList' returns the list of fonts that match a given
+   pattern on a certain set of properties.  `FcFontSort' returns the
+   entire list of fonts, sorted in order of match quality, possibly
+   filtering out fonts that do not provide additional characters beyond
+   those provided by preferred fonts. */
+
+DEFUN("fc-font-render-prepare", Ffc_font_render_prepare, 2, 3, 0, /*
+Return a new pattern blending PATTERN and FONT.
+Optional CONFIG is an FcConfig, defaulting to the current one.
+The returned pattern consists of elements of FONT not appearing in PATTERN,
+elements of PATTERN not appearing in FONT, and the best matching value from
+PATTERN for elements appearing in both.  The result is passed to
+FcConfigSubstitute with 'kind' FcMatchFont and then returned. */
+      (pattern, font, config))
+{
+  if (NILP (config)) {
+    config = Ffc_config_get_current ();
+  }
+  CHECK_FCPATTERN (pattern);
+  CHECK_FCPATTERN (font);
+  CHECK_FCCONFIG (config);
+
+  /* I don't think this can fail? */
+  return wrap_fcpattern (FcFontRenderPrepare (XFCCONFIG_PTR(config),
+					      XFCPATTERN_PTR(font),
+					      XFCPATTERN_PTR(pattern)));
+}
+
+DEFUN("fc-font-match", Ffc_font_match, 2, 3, 0, /*
+Return the font on DEVICE that most closely matches PATTERN.
+
+DEVICE is an X11 device.
+PATTERN is a fontconfig pattern object.
+Optional CONFIG is an FcConfig, defaulting to the current one.
+Returns a fontconfig pattern object representing the closest match to the
+given pattern, or an error code.  Possible error codes are
+`fc-result-no-match' and `fc-result-no-id'.
+PATTERN is massaged with FcConfigSubstitute and FcDefaultSubstitute before
+being processed by FcFontMatch. */
+      (device, pattern, config))
+{
+  FcResult res;
+  struct fc_pattern *res_fcpat;
+  FcPattern *p;
+  FcConfig *fcc;
+
+  CHECK_FCPATTERN(pattern);
+  if (NILP(device))
+    return Qnil;
+  CHECK_X_DEVICE(device);
+  if (!DEVICE_LIVE_P(XDEVICE(device)))
+    return Qnil;
+  if (!NILP (config))
+    CHECK_FCCONFIG (config);
+
+  res_fcpat = ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
+  p = XFCPATTERN_PTR(pattern);
+  fcc = NILP (config) ? FcConfigGetCurrent () : XFCCONFIG_PTR (config);
+
+  FcConfigSubstitute (fcc, p, FcMatchPattern);
+  FcDefaultSubstitute (p);
+  res_fcpat->fcpatPtr = FcFontMatch (fcc, p, &res);
+
+  if (res_fcpat->fcpatPtr == NULL)
+    switch (res) {
+    case FcResultNoMatch:
+      return Qfc_result_no_match;
+    case FcResultNoId:
+      return Qfc_result_no_id;
+    default:
+      return Qfc_internal_error;
+    }
+  else
+    return wrap_fcpattern(res_fcpat);
+}
+
+/* #### fix this name to correspond to Ben's new nomenclature */
+DEFUN("fc-list-fonts-pattern-objects", Ffc_list_fonts_pattern_objects,
+      3, 3, 0, /*
+Return a list of fonts on DEVICE that match PATTERN for PROPERTIES.
+Each font is represented by a fontconfig pattern object.
+
+DEVICE is an X11 device.
+PATTERN is a fontconfig pattern to be matched.
+PROPERTIES is a list of property names (strings) that should match.
+
+#### DEVICE is unused, ignored, and may be removed if it's not needed to
+match other font-listing APIs. */
+      (UNUSED (device), pattern, properties))
+{
+  FcObjectSet *os;
+  FcFontSet *fontset;
+
+  CHECK_FCPATTERN (pattern);
+  CHECK_LIST (properties);
+
+  os = FcObjectSetCreate ();
+  string_list_to_fcobjectset (properties, os);
+  /* #### why don't we need to do the "usual substitutions"? */
+  fontset = FcFontList (NULL, XFCPATTERN_PTR (pattern), os);
+  FcObjectSetDestroy (os);
+
+  return fontset_to_list (fontset, DestroyYes);
+
+}
+
+/* #### maybe this can/should be folded into fc-list-fonts-pattern-objects? */
+DEFUN("fc-font-sort", Ffc_font_sort, 2, 4, 0, /*
+Return a list of all fonts sorted by proximity to PATTERN.
+Each font is represented by a fontconfig pattern object.
+
+DEVICE is an X11 device.
+PATTERN is a fontconfig pattern to be matched.
+Optional argument TRIM, if non-nil, means to trim trailing fonts that do not
+contribute new characters to the union repertoire.
+
+#### Optional argument NOSUB, if non-nil, suppresses some of the usual
+property substitutions.  DON'T USE THIS in production code, it is intended
+for exploring behavior of fontconfig and will be removed when this code is
+stable.
+
+#### DEVICE is unused, ignored, and may be removed if it's not needed to
+match other font-listing APIs. */
+      (UNUSED (device), pattern, trim, nosub))
+{
+  CHECK_FCPATTERN (pattern);
+
+  {
+    FcConfig *fcc = FcConfigGetCurrent();
+    FcFontSet *fontset;
+    FcPattern *p = XFCPATTERN_PTR (pattern);
+    FcResult fcresult;
+
+    if (NILP(nosub))		/* #### temporary debug hack */
+      FcDefaultSubstitute (p);
+    FcConfigSubstitute (fcc, p, FcMatchPattern);
+    fontset = FcFontSort (fcc, p, !NILP(trim), NULL, &fcresult);
+
+    return fontset_to_list (fontset, DestroyYes);
+  }
+}
+
+#ifdef FONTCONFIG_EXPOSE_CONFIG
+
+/* Configuration routines --- for debugging
+   Don't depend on these routines being available in the future!
+
+   3.2.10 Initialization
+   ---------------------
+
+   An FcConfig object holds the internal representation of a configuration.
+   There is a default configuration which applications may use by passing
+   0 to any function using the data within an FcConfig.
+*/
+
+static void
+finalize_fc_config (void *header, int UNUSED (for_disksave))
+{
+  struct fc_config *p = (struct fc_config *) header;
+  if (p->fccfgPtr && p->fccfgPtr != FcConfigGetCurrent())
+    {
+      /* If we get here, all of *our* references are garbage (see comment on
+	 fc_config_create_using() for why), and the only reference that
+	 fontconfig keeps is the current FcConfig. */
+      FcConfigDestroy (p->fccfgPtr);
+    }
+  p->fccfgPtr = 0;
+}
+
+static void
+print_fc_config (Lisp_Object obj, Lisp_Object printcharfun,
+		 int UNUSED(escapeflag))
+{
+  struct fc_config *c = XFCCONFIG (obj);
+  if (print_readably)
+    printing_unreadable_object ("#<fc-config 0x%x>", c->header.uid);
+  write_fmt_string (printcharfun, "#<fc-config 0x%x>", c->header.uid);
+}
+
+static const struct memory_description fcconfig_description [] = {
+  /* #### nothing here, is this right?? */
+  { XD_END }
+};
+
+DEFINE_LRECORD_IMPLEMENTATION("fc-config", fc_config, 0,
+			      0, print_fc_config, finalize_fc_config, 0, 0,
+			      fcconfig_description,
+			      struct fc_config);
+
 DEFUN("fc-init", Ffc_init, 0, 0, 0, /*
  -- Function: FcBool FcInit (void)
      Loads the default configuration file and the fonts referenced
@@ -1192,8 +1296,7 @@
 }
 
 void
-syms_of_font_mgr (void)
-{
+syms_of_font_mgr (void) {
   INIT_LRECORD_IMPLEMENTATION(fc_pattern);
 
   DEFSYMBOL_MULTIWORD_PREDICATE(Qfc_patternp);
@@ -1202,6 +1305,8 @@
   DEFSYMBOL(Qfc_result_no_match);
   DEFSYMBOL(Qfc_result_no_id);
   DEFSYMBOL(Qfc_internal_error);
+  DEFSYMBOL(Qfc_match_pattern);
+  DEFSYMBOL(Qfc_match_font);
   DEFSYMBOL(Qfont_mgr);
 
   DEFSUBR(Ffc_pattern_p);
@@ -1215,6 +1320,9 @@
   DEFSUBR(Ffc_list_fonts_pattern_objects);
   DEFSUBR(Ffc_font_sort);
   DEFSUBR(Ffc_font_match);
+  DEFSUBR(Ffc_default_substitute);
+  DEFSUBR(Ffc_config_substitute);
+  DEFSUBR(Ffc_font_render_prepare);
   DEFSUBR(Fxlfd_font_name_p);
 
 #ifdef FONTCONFIG_EXPOSE_CONFIG
--- a/src/font-mgr.h	Wed Nov 18 15:25:00 2009 +0900
+++ b/src/font-mgr.h	Wed Nov 18 22:44:28 2009 +0900
@@ -157,14 +157,11 @@
 
 /* print a progress message
    LEVEL is the debug level (to compare to debug_xft)
-   FONT is the Xft font name in UTF-8 (the native encoding of Xft)
+   FONT is the Xft font name in Mule internal encoding (from an eistring).
    LANG is the language being checked for support (must be ASCII). */
 #define CHECKING_LANG(level,font,lang)					\
   do {									\
-    DECLARE_EISTRING (eistrcl_name);					\
-    eicpy_ext(eistrcl_name, font, Qfc_font_name_encoding);		\
-    DEBUG_XFT2 (level, "checking if %s handles %s\n",			\
-			eidata(eistrcl_name), lang);			\
+    DEBUG_XFT2 (level, "checking if %s handles %s\n", font, lang);	\
   } while (0)
 
 #else /* USE_XFT */
--- a/src/objects-xlike-inc.c	Wed Nov 18 15:25:00 2009 +0900
+++ b/src/objects-xlike-inc.c	Wed Nov 18 22:44:28 2009 +0900
@@ -328,7 +328,8 @@
   Lisp_Object *charset;
   /* This is a debug facility, require ASCII. */
   Extbyte *language;		/* ASCII, please */
-  /* Technically this is FcChar8, but fsckin' GCC 4 bitches. */
+  /* Technically this is FcChar8, but fsckin' GCC 4 bitches.
+     RFC 3066 is a combination of ISO 639 and ISO 3166. */
   Extbyte *rfc3066;		/* ASCII, please */
 };
 
@@ -416,9 +417,7 @@
 				   failure, but that looks like a bug.  We
 				   check for it with FcGetCurrentConfig(),
 				   which *can* fail. */
-  if (!FcConfigGetCurrent())	/* #### We should expose FcInit* interfaces
-				   to LISP and decide when to reinitialize
-				   intelligently. */
+  if (!FcConfigGetCurrent())
     stderr_out ("Failed fontconfig initialization\n");
   else
     {
@@ -470,14 +469,14 @@
       */
       {
 	FcPattern *p = FcFontRenderPrepare (fcc, fontxft, fontxft);
-	FcChar8 *name;
+	Extbyte *name;
 
 	/* full name, including language coverage and repertoire */
-	name = FcNameUnparse (p);
+	name = (Extbyte *) FcNameUnparse (p);
 	eicpy_ext (eistr_fullname,
-		   (Extbyte *) (name ? name : "NOT FOUND"),
+		   (name ? name : "NOT FOUND"),
 		   Qfc_font_name_encoding);
-	free (name);
+	if (name) free (name);
 
 	/* long name, omitting coverage and repertoire, plus a number
 	   of rarely useful properties */
@@ -494,11 +493,11 @@
 	FcPatternDel (p, FC_INDEX);
 	FcPatternDel (p, FC_SCALE);
 	FcPatternDel (p, FC_FONTVERSION);
-	name = FcNameUnparse (p);
+	name = (Extbyte *) FcNameUnparse (p);
 	eicpy_ext (eistr_longname,
-		   (Extbyte *) (name ? name : "NOT FOUND"),
+		   (name ? name : "NOT FOUND"),
 		   Qfc_font_name_encoding);
-	free (name);
+	if (name) free (name);
 
 	/* nickname, just family and size, but
 	   "family" names usually have style, slant, and weight */
@@ -510,11 +509,11 @@
 	FcPatternDel (p, FC_OUTLINE);
 	FcPatternDel (p, FC_SCALABLE);
 	FcPatternDel (p, FC_DPI);
-	name = FcNameUnparse (p);
+	name = (Extbyte *) FcNameUnparse (p);
 	eicpy_ext (eistr_shortname,
-		   (Extbyte *) (name ? name : "NOT FOUND"),
+		   (name ? name : "NOT FOUND"),
 		   Qfc_font_name_encoding);
-	free (name);
+	if (name) free (name);
 
 	FcPatternDestroy (p);
       }