Hi Till and Martin,

please find my improved patch attached.

If direct loading of the TTF font file passed to font_load() fails, turn the file name into a fontconfig "pattern" (see below!) and use it to receive a list of similar fonts from fontconfig that somehow match this pattern. Then iterate through this list to find the first candidate that is both in TrueType format and monospaced. If none is found, fontname will still point to NULL and the function returns NULL just as before.

With this patch, texttopdf should work whether ttf-freefonts is installed or not, whether the symlinks are there or not, whether they are dangling or not - it just shouldn't matter, *as long as at least on monospaced TrueType font is installed on the system*. This may be provided by fonts-liberation, ttf-dejavu, fonts-consolidata or whatever. However, if ttf-freefonts is installed, the symlinks will point to these fonts and they take preference over all the others. I think this still makes sense, because ttf-freefonts may still have the widest unicode coverage of them all. I think this fact should also get reflected in the package dependencies, which could get changed from "Depends: ttf-freefonts" to "Depends: ttf-freefonts | fonts-liberation | ttf-dejavu" or similar. This would close #662660 and #495598. ;)

There is one drawback with this patch (but I think the net win overweights): The file names passed to font_load() are in fact no valid fontconfig patterns, even with their .ttf extensions removed. That is, fontconfig cannot know that "FreeMonoBold" means that we want the bold face of the FreeMono or any other valid monospaced font. I should be called "FreeMono:Bold" to achieve this, but this in turn is incompatible with the file names found in ttf-freefonts. I think it still works well enough as a fallback as it is now, but in the long term one should consider switching from actual font file names to fontconfig patterns in pdf.utf-8.* altogether!

Another warning: This is my very first encounter with fontconfig, so I suggest someone with a bit more fontconfig-fu should have a look at it before applying it upstream. ;)

Regards,
 - Fabian


PS: The cups-filters package currently FTBFS if built twice in a row, because there are object files left in pdftoopvp/oprs/ and filter/fontembed/. Maybe those two directories should get added to the DIRS variable in the top-level Makefile.
--- cups-filters-1.0.2.orig/filter/Makefile
+++ cups-filters-1.0.2/filter/Makefile
@@ -329,7 +329,7 @@ fontembed/libfontembed.a:
 
 texttopdf:	texttopdf.o textcommon.o common.o pdfutils.o fontembed/libfontembed.a
 	echo Linking $@...
-	$(CC) $(LDFLAGS) -o $@ texttopdf.o textcommon.o common.o pdfutils.o -Lfontembed -lfontembed $(LIBS)
+	$(CC) $(LDFLAGS) -o $@ texttopdf.o textcommon.o common.o pdfutils.o -Lfontembed -lfontembed $(FONTCONFIG_LIBS) $(LIBS)
 
 
 #
--- cups-filters-1.0.2.orig/filter/texttopdf.c
+++ cups-filters-1.0.2/filter/texttopdf.c
@@ -32,6 +32,8 @@
 #include "fontembed/embed.h"
 #include <assert.h>
 #include "fontembed/sfnt.h"
+#include <fontconfig/fontconfig.h>
+#include <string.h>
 
 /*
  * Globals...
@@ -49,6 +51,44 @@ EMB_PARAMS *font_load(const char *datadi
   snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, font);
 
   OTF_FILE *otf=otf_load(filename);
+
+  if (!otf) {
+
+    FcPattern *pattern;
+    FcFontSet *candidates;
+    FcChar8   *fontformat, *fontname = NULL;
+    int i, spacing;
+
+    /* Remove extension from the passed file name
+       to turn it into a minimal "pattern" in the fontconfig sense */
+    if (strrchr(filename, '.'))
+       *strrchr(filename, '.') = '\0';
+
+    FcInit ();
+    pattern = FcNameParse (filename);
+    FcConfigSubstitute (0, pattern, FcMatchPattern);
+    FcDefaultSubstitute (pattern);
+
+    /* Receive a sorted list of fonts matching our pattern */
+    candidates = FcFontSort (0, pattern, FcTrue, 0, 0);
+    FcPatternDestroy (pattern);
+
+    /* In the list of fonts returned by FcFontSort()
+       find the first one that is both in TrueType format and monospaced */
+    for (i = 0; i < candidates->nfont; i++) {
+      FcPatternGetString  (candidates->fonts[i], FC_FONTFORMAT, 0, &fontformat);
+      FcPatternGetInteger (candidates->fonts[i], FC_SPACING,    0, &spacing);
+
+      if ((strcmp(fontformat, "TrueType") == 0) && (spacing == FC_MONO)) {
+        fontname = FcPatternFormat (candidates->fonts[i], "%{file|cescape}");
+        break;
+      }
+    }
+    FcFontSetDestroy (candidates);
+
+    otf = otf_load(fontname);
+  }
+
   if (!otf) {
     // TODO: try /usr/share/fonts/*/*/%s.ttf
     return NULL;

Reply via email to