freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft-devel] a flag making FT_Open_Face() to use fallback family name


From: mpsuzuki
Subject: [ft-devel] a flag making FT_Open_Face() to use fallback family name
Date: Fri, 27 Aug 2010 00:00:32 +0900

Sorry for posting so many.

In previous post, I proposed a patch to expose the tricky
font list to FT2 client, to check if the font is tricky by
its name before the creation of FT_Face object:
        http://lists.gnu.org/archive/html/freetype-devel/2010-08/msg00018.html

The reason why the name only without font data is that
Type42/Type11 TrueType font may lack "name" table (and FT2
cannot know the font name from the font file).

I've tried another idea to reduce the additional code size:
an introduction of new flag for FT_Open_Face(), to pass
a fallback family name. By using the flag, FT_Open_Face()
uses the fallback family name (taken from the optional
parameters) when sfnt data lacks "name" table.

Or, should I use FT_Face_Attach function for TrueType?
At present, the feature is only used by PS Type1 font to
add the metric infos stored in external AFM/PFM file.
It may be possible (in technical meaning) to write a function
to add/overwrite the information taken from PDF font
descriptor stream (e.g. PS font name, StemV, Ascent, Descent,
ItalicAngle, CapHeight, FontBBox etc). However, the attempt
to overwrite something in TrueType is not PDF-specific issue,
so the usage of the attach feature must be considered well.
If you think FT_Face_Attach is better than passing fallback
family name flag to FT_Open_Face(), please ignore following
part of this post, and give me short comment.

Regards,
mpsuzuki

==========================================================

The patch to add fallback family name feature is following:
diff --git a/include/freetype/ftsnames.h b/include/freetype/ftsnames.h
index 485e4e1..7e95229 100644
--- a/include/freetype/ftsnames.h
+++ b/include/freetype/ftsnames.h
@@ -189,6 +189,22 @@ FT_BEGIN_HEADER
    */
 #define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY  FT_MAKE_TAG( 'i', 'g', 'p', 
's' )
 
+
+  /***************************************************************************
+   *
+   * @constant:
+   *   FT_PARAM_TAG_FALLBACK_NAME_FAMILY
+   *
+   * @description:
+   *   A constant used as the tag of @FT_Parameter structures to specify
+   *   a fallback family name. The embedded TrueType font in Type42 or
+   *   Type11 format may lack the name table in its sfnt stream. To make
+   *   FT_Face object with valid family name for such fonts, this option
+   *   should be used.
+   *
+   */
+#define FT_PARAM_TAG_FALLBACK_NAME_FAMILY  FT_MAKE_TAG( 'f', 'b', 'n', 'f' )
+
   /* */
 
 
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 6e35e2d..5e64046 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -530,6 +530,7 @@
     FT_Bool       is_apple_sbit;
     FT_Bool       ignore_preferred_family = FALSE;
     FT_Bool       ignore_preferred_subfamily = FALSE;
+    FT_String*    fallback_name_family = NULL;
 
     SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
 
@@ -543,10 +544,25 @@
 
       for ( i = 0; i < num_params; i++ )
       {
-        if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY )
-          ignore_preferred_family = TRUE;
-        else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY )
-          ignore_preferred_subfamily = TRUE;
+        switch( params[i].tag )
+        {
+          case FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY:
+            ignore_preferred_family = TRUE;
+            break;
+          case FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY:
+            ignore_preferred_subfamily = TRUE;
+            break;
+          case FT_PARAM_TAG_FALLBACK_NAME_FAMILY:
+            fallback_name_family = (FT_String*)params[i].data;
+            break;
+          default:
+            FT_TRACE2(( "sfnt_load_face: ignore unknown FT_Param"
+                        " tagged [%c%c%c%c]\n",
+                        ( params[i].tag >> 24 ) & 0xFF,
+                        ( params[i].tag >> 16 ) & 0xFF,
+                        ( params[i].tag >>  8 ) & 0xFF,
+                        ( params[i].tag       ) & 0xFF ));
+        }
       }
     }
 
@@ -766,6 +782,21 @@
         GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
     }
 
+    /* fallback for empty names */
+    {
+      FT_Memory  memory = face->root.stream->memory;
+      FT_UInt    len;
+
+
+      if ( !face->root.family_name && fallback_name_family )
+      {
+        len = ft_strlen( fallback_name_family );
+        if ( !FT_NEW_ARRAY( face->root.family_name, len + 1 ) )
+          ft_memcpy( face->root.family_name, fallback_name_family, len + 1 );
+      }
+      /* subfamily/styles are needed? */
+    }
+
     /* now set up root fields */
     {
       FT_Face  root  = &face->root;


-------------------------------------------------------------------

Maybe it is not easy to understand how to use this.
The patch for freetype2-demos attached to the end of this
message. It modifies ftdump & ftview and add "-F" option
to specify the fallback family name. It works aslike:

        $ ./ftdump ./dell440_037-000.ttf 
        There is 1 face in this file.

        ----- Face number: 0 -----

        font name entries
        family:     (null)
        style:      (null)
        postscript: UNAVAILABLE

        ...


        $ ./ftdump -F MingLiU ./dell440_037-000.ttf 
        There is 1 face in this file.

        ----- Face number: 0 -----

        font name entries
        family:     MingLiU
        style:      (null)
        postscript: UNAVAILABLE

        ...

Some people will wonder "so what? what is the advantage
of such joking feature?". Please try ftview. If you
execute ftview for dell440_037-000.ttf without fallback
family name, the hinting switch will work - if hinted,
the glyph is correct, if unhinted, the glyph is broken.

Maybe it sounds odd, this is NOT what the residents in
the world of flooding MingLiU. What they (including me)
expect is: even if FT_New_Face() is invoked with FT_LOAD_NO_HINTING,
the hinter should be enabled. So the hinting switch changes
nothing for MingLiU is expected. If you try genuine MingLiU
not subsetted, you will find such behaviour. This hook is
realized by the tricky font list.

Then, if you execute with fallback family name,

        $ ./ftview -F MingLiU 40 ./dell440_037-000.ttf 

You will find hinting is always enabled and the switch
does not change anything. This is the behaviour that
the residents in the world of flooding MingLiU expect.

The patch for freetype2-demos is following:

diff --git a/src/ftcommon.c b/src/ftcommon.c
index 8a60c15..938dace 100644
--- a/src/ftcommon.c
+++ b/src/ftcommon.c
@@ -17,6 +17,7 @@
 #include FT_CACHE_H
 #include FT_CACHE_MANAGER_H
 
+#include FT_SFNT_NAMES_H
 #include FT_BITMAP_H
 
 #include "common.h"
@@ -191,6 +192,34 @@
   };
 
 
+  static FT_Error
+  ft_new_face_with_params( FT_Library     library,
+                           const char*    pathname,
+                           FT_UInt        face_index,
+                           FT_UInt        num_params,
+                           FT_Parameter*  params,
+                           FT_Face*       aface )
+  {
+    FT_Error      error = FT_Err_Invalid_Argument;
+    FT_Open_Args  args;
+
+    if ( !pathname )
+      return error;
+
+    args.flags    = FT_OPEN_PATHNAME;
+    args.pathname = (char*)pathname;
+    args.stream   = NULL;
+
+    if ( num_params > 0 )
+    {
+      args.flags     |= FT_OPEN_PARAMS;
+      args.num_params = num_params;
+      args.params     = params;
+    } 
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+
   /*************************************************************************/
   /*                                                                       */
   /* The face requester is a function provided by the client application   */
@@ -206,6 +235,8 @@
                      FT_Face*    aface )
   {
     PFont  font = (PFont)face_id;
+    FT_Parameter  param = { FT_PARAM_TAG_FALLBACK_NAME_FAMILY,
+                            font->fallback_name_family };
 
     FT_UNUSED( request_data );
 
@@ -216,10 +247,12 @@
                                   font->face_index,
                                   aface );
     else
-      error = FT_New_Face( lib,
-                           font->filepathname,
-                           font->face_index,
-                           aface );
+      error = ft_new_face_with_params( lib,
+                                       font->filepathname,
+                                       font->face_index,
+                                       1, &param,
+                                       aface );
+
     if ( !error )
     {
       char*  suffix;
@@ -344,11 +377,13 @@
 
 
   FT_Error
-  FTDemo_Install_Font( FTDemo_Handle*  handle,
-                       const char*     filepath )
+  FTDemo_Install_Font_With_Params( FTDemo_Handle*  handle,
+                                   const char*     filepath,
+                                   FT_UInt         num_params,
+                                   FT_Parameter*   params )
   {
     static char  filename[1024 + 5];
-    int          i, len, num_faces;
+    int          i, j, len, num_faces;
     FT_Face      face;
 
 
@@ -359,8 +394,8 @@
     strncpy( filename, filepath, len );
     filename[len] = 0;
 
-    error = FT_New_Face( handle->library, filename, 0, &face );
-
+    error = ft_new_face_with_params( handle->library, filename, 0,
+                                     num_params, params, &face );
 #ifndef macintosh
     /* could not open the file directly; we will now try various */
     /* suffixes like `.ttf' or `.pfb'                            */
@@ -390,7 +425,8 @@
         /* try with current suffix */
         strcpy( p, suffix[0] );
 
-        error = FT_New_Face( handle->library, filename, 0, &face );
+        error = ft_new_face_with_params( handle->library, filename, 0,
+                                         num_params, params, &face );
         if ( !error )
         {
           found = 1;
@@ -414,7 +450,8 @@
 
       if ( i > 0 )
       {
-        error = FT_New_Face( handle->library, filename, i, &face );
+        error = ft_new_face_with_params( handle->library, filename, i,
+                                         num_params, params, &face );
         if ( error )
           continue;
       }
@@ -434,6 +471,14 @@
       font->filepathname = (char*)malloc( strlen( filename ) + 1 );
       strcpy( (char*)font->filepathname, filename );
 
+      font->fallback_name_family = NULL;
+      for ( j = 0; j < num_params; j++ )
+        if ( params[j].tag == FT_PARAM_TAG_FALLBACK_NAME_FAMILY )
+        {
+          font->fallback_name_family = (char*)malloc( strlen( params[j].data ) 
);
+          strcpy( (char*)font->fallback_name_family, params[j].data );
+        }
+
       font->face_index = i;
       font->cmap_index = face->charmap ? FT_Get_Charmap_Index( face->charmap )
                                        : 0;
@@ -520,6 +565,14 @@
   }
 
 
+  FT_Error
+  FTDemo_Install_Font( FTDemo_Handle*  handle,
+                       const char*     filepath )
+  {
+    return FTDemo_Install_Font_With_Params( handle, filepath, 0, NULL );
+  }
+
+
   void
   FTDemo_Set_Current_Font( FTDemo_Handle*  handle,
                            PFont           font )
diff --git a/src/ftcommon.h b/src/ftcommon.h
index e6ce02f..10875c2 100644
--- a/src/ftcommon.h
+++ b/src/ftcommon.h
@@ -117,6 +117,8 @@
     void*        file_address;  /* for preloaded files */
     size_t       file_size;
 
+    /* FT_Face object may be recreated, so info for recreation should be 
stored in PFont */
+    FT_String*   fallback_name_family;
   } TFont, *PFont;
 
   enum {
@@ -206,6 +208,13 @@
 
   /* install a font */
   FT_Error
+  FTDemo_Install_Font_With_Params( FTDemo_Handle*  handle,
+                                   const char*     filepath,
+                                   FT_UInt         num_params,
+                                   FT_Parameter*   params );
+
+
+  FT_Error
   FTDemo_Install_Font( FTDemo_Handle*  handle,
                        const char*     filepath );
 
diff --git a/src/ftdump.c b/src/ftdump.c
index 3bb7fc0..d35e2d4 100644
--- a/src/ftdump.c
+++ b/src/ftdump.c
@@ -36,6 +36,7 @@
   int  debug       = 0;
   int  trace_level = 0;
   int  name_tables = 0;
+  char*  fallback_name_family = NULL;
 
 
   /* PanicZ */
@@ -73,6 +74,7 @@
     fprintf( stderr, "  -l level  trace level for debug information\n" );
 #  endif
 #endif
+    fprintf( stderr, "  -F        fallback family name\n" );
     fprintf( stderr, "  -n        print SFNT name tables\n" );
     fprintf( stderr, "  -v        be verbose\n" );
     fprintf( stderr, "\n" );
@@ -557,7 +559,7 @@
 
     while ( 1 )
     {
-      option = getopt( argc, argv, "dl:nv" );
+      option = getopt( argc, argv, "dl:F:nv" );
 
       if ( option == -1 )
         break;
@@ -574,6 +576,10 @@
           usage( execname );
         break;
 
+      case 'F':
+        fallback_name_family = optarg;
+        break;
+
       case 'n':
         name_tables = 1;
         break;
@@ -666,7 +672,30 @@
 
     for ( i = 0; i < num_faces; i++ )
     {
+#if 0
       error = FT_New_Face( library, filename, i, &face );
+#else
+      {
+        error = FT_Err_Invalid_Argument;
+        if ( filename[0] )
+        {
+          FT_Open_Args  args;
+          FT_Parameter  param;
+
+
+          args.flags    = FT_OPEN_PATHNAME | FT_OPEN_PARAMS;
+          args.pathname = (char*)filename;
+          args.stream   = NULL;
+
+          param.tag     = FT_PARAM_TAG_FALLBACK_NAME_FAMILY;
+          param.data    = fallback_name_family;
+          args.params   = &param;
+          args.num_params = 1;
+
+          error = FT_Open_Face( library, &args, i, &face );
+        }
+      } 
+#endif
       if ( error )
         PanicZ( "Could not open face." );
 
diff --git a/src/ftview.c b/src/ftview.c
index 42ed67c..d132e36 100644
--- a/src/ftview.c
+++ b/src/ftview.c
@@ -26,6 +26,7 @@
 #include FT_STROKER_H
 #include FT_SYNTHESIS_H
 #include FT_LCD_FILTER_H
+#include FT_SFNT_NAMES_H
 
 #define MAXPTSIZE      500                 /* dtp */
 #define HEADER_HEIGHT  8
@@ -92,11 +93,12 @@
     int            use_custom_lcd_filter;
     unsigned char  filter_weights[5];
     int            fw_index;
+    char*          fallback_name_family;
 
   } status = { RENDER_MODE_ALL, FT_ENCODING_NONE, 72, 48, -1,
                1.0, 0.04, 0.22,
                0, 0, 0, 0, 0, NULL, { 0 }, 0, 0,
-               0, "\x10\x40\x70\x40\x10", 2 };
+               0, "\x10\x40\x70\x40\x10", 2, NULL };
 
 
   static FTDemo_Display*  display;
@@ -1247,6 +1249,7 @@
     fprintf( stderr,  "            `.afm' or `.pfm').\n" );
     fprintf( stderr,  "\n" );
     fprintf( stderr,  "  -r R      Use resolution R dpi (default: 72 dpi).\n" 
);
+    fprintf( stderr,  "  -F name   Specify fallback family name.\n" );
     fprintf( stderr,  "  -f index  Specify first index to display.\n" );
     fprintf( stderr,  "  -e enc    Specify encoding tag (default: no 
encoding).\n" );
     fprintf( stderr,  "  -D        Dump cache usage statistics.\n" );
@@ -1272,7 +1275,7 @@
 
     while ( 1 )
     {
-      option = getopt( *argc, *argv, "Dde:f:L:l:r:m:p" );
+      option = getopt( *argc, *argv, "Dde:F:f:L:l:r:m:p" );
 
       if ( option == -1 )
         break;
@@ -1291,6 +1294,10 @@
         status.encoding = FTDemo_Make_Encoding_Tag( optarg );
         break;
 
+      case 'F':
+        status.fallback_name_family  = optarg;
+        break;
+
       case 'f':
         status.Num  = atoi( optarg );
         break;
@@ -1386,7 +1393,14 @@
       FTDemo_Set_Preload( handle, 1 );
 
     for ( ; argc > 0; argc--, argv++ )
-      FTDemo_Install_Font( handle, argv[0] );
+    {
+      FT_Parameter  param;
+
+
+      param.tag  = FT_PARAM_TAG_FALLBACK_NAME_FAMILY;
+      param.data = status.fallback_name_family;
+      FTDemo_Install_Font_With_Params( handle, argv[0], 1, &param );
+    }
 
     if ( handle->num_fonts == 0 )
       Fatal( "could not find/open any font file" );

Attachment: dell440_037-000.ttf.bz2
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]