Sync with trunk r47367
[reactos.git] / lib / 3rdparty / freetype / src / sfnt / sfobjs.c
index cc90110..b74b1a9 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    SFNT object management (base).                                       */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by             */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by       */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -26,6 +26,7 @@
 #include FT_TRUETYPE_IDS_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
+#include FT_SFNT_NAMES_H
 #include "sferrors.h"
 
 #ifdef TT_CONFIG_OPTION_BDF
   /*                                                                       */
   /*    nameid :: The name id of the name record to return.                */
   /*                                                                       */
+  /* <InOut>                                                               */
+  /*    name   :: The address of a string pointer.  NULL if no name is     */
+  /*              present.                                                 */
+  /*                                                                       */
   /* <Return>                                                              */
-  /*    Character string.  NULL if no name is present.                     */
+  /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
-  static FT_String*
-  tt_face_get_name( TT_Face    face,
-                    FT_UShort  nameid )
+  static FT_Error
+  tt_face_get_name( TT_Face      face,
+                    FT_UShort    nameid,
+                    FT_String**  name )
   {
     FT_Memory         memory = face->root.memory;
+    FT_Error          error  = SFNT_Err_Ok;
     FT_String*        result = NULL;
     FT_UShort         n;
     TT_NameEntryRec*  rec;
     TT_NameEntry_ConvertFunc  convert;
 
 
+    FT_ASSERT( name );
+
     rec = face->name_table.names;
     for ( n = 0; n < face->num_names; n++, rec++ )
     {
     {
       if ( rec->string == NULL )
       {
-        FT_Error   error  = SFNT_Err_Ok;
         FT_Stream  stream = face->name_table.stream;
 
-        FT_UNUSED( error );
-
 
         if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) ||
              FT_STREAM_SEEK( rec->stringOffset )              ||
     }
 
   Exit:
-    return result;
+    *name = result;
+    return error;
   }
 
 
   sfnt_find_encoding( int  platform_id,
                       int  encoding_id )
   {
-    typedef struct  TEncoding
+    typedef struct  TEncoding_
     {
       int          platform_id;
       int          encoding_id;
     if ( FT_READ_ULONG( tag ) )
       return error;
 
-    if ( tag != 0x00010000UL                      &&
-         tag != TTAG_ttcf                         &&
-         tag != FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) &&
-         tag != TTAG_true                         &&
-         tag != 0x00020000UL                      )
+    if ( tag != 0x00010000UL &&
+         tag != TTAG_ttcf    &&
+         tag != TTAG_OTTO    &&
+         tag != TTAG_true    &&
+         tag != TTAG_typ1    &&
+         tag != 0x00020000UL )
       return SFNT_Err_Unknown_File_Format;
 
     face->ttc_header.tag = TTAG_ttcf;
       face->ttc_header.version = 1 << 16;
       face->ttc_header.count   = 1;
 
-      if ( FT_NEW( face->ttc_header.offsets) )
+      if ( FT_NEW( face->ttc_header.offsets ) )
         return error;
 
       face->ttc_header.offsets[0] = offset;
       face_index = 0;
 
     if ( face_index >= face->ttc_header.count )
-        return SFNT_Err_Bad_Argument;
+      return SFNT_Err_Invalid_Argument;
 
     if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) )
       return error;
     if ( error )
       return error;
 
-    face->root.num_faces = face->ttc_header.count;
+    face->root.num_faces  = face->ttc_header.count;
+    face->root.face_index = face_index;
 
     return error;
   }
     FT_TRACE3(( "\n" ));                                      \
   } while ( 0 )
 
+#define GET_NAME( id, field )                                 \
+  do {                                                        \
+    error = tt_face_get_name( face, TT_NAME_ID_##id, field ); \
+    if ( error )                                              \
+      goto Exit;                                              \
+  } while ( 0 )
+
 
   FT_LOCAL_DEF( FT_Error )
   sfnt_load_face( FT_Stream      stream,
                   FT_Int         num_params,
                   FT_Parameter*  params )
   {
-    FT_Error      error, psnames_error;
+    FT_Error      error;
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+    FT_Error      psnames_error;
+#endif
     FT_Bool       has_outline;
     FT_Bool       is_apple_sbit;
+    FT_Bool       ignore_preferred_family = FALSE;
+    FT_Bool       ignore_preferred_subfamily = FALSE;
 
     SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
 
     FT_UNUSED( face_index );
-    FT_UNUSED( num_params );
-    FT_UNUSED( params );
 
+    /* Check parameters */
+    
+    {
+      FT_Int  i;
+
+
+      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;
+      }
+    }
 
     /* Load tables */
 
     /* don't check for errors                            */
     LOAD_( name );
     LOAD_( post );
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
     psnames_error = error;
+#endif
 
     /* do not load the metrics headers and tables if this is an Apple */
     /* sbit font file                                                 */
 
         face->os2.version = 0xFFFFU;
       }
-
     }
 
     /* the optional tables */
 
-    /* embedded bitmap support. */
+    /* embedded bitmap support */
     if ( sfnt->load_eblc )
     {
       LOAD_( eblc );
       if ( error )
       {
-        /* return an error if this font file has no outlines */
-        if ( error == SFNT_Err_Table_Missing && has_outline )
+        /* a font which contains neither bitmaps nor outlines is */
+        /* still valid (although rather useless in most cases);  */
+        /* however, you can find such stripped fonts in PDFs     */
+        if ( error == SFNT_Err_Table_Missing )
           error = SFNT_Err_Ok;
         else
           goto Exit;
     LOAD_( gasp );
     LOAD_( kern );
 
-    error = SFNT_Err_Ok;
-
     face->root.num_glyphs = face->max_profile.numGlyphs;
 
-    face->root.family_name = tt_face_get_name( face,
-                                               TT_NAME_ID_PREFERRED_FAMILY );
-    if ( !face->root.family_name )
-      face->root.family_name = tt_face_get_name( face,
-                                                 TT_NAME_ID_FONT_FAMILY );
+    /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes  */
+    /* a WWS-only font face.  `WWS' stands for `weight', width', and */
+    /* `slope', a term used by Microsoft's Windows Presentation      */
+    /* Foundation (WPF).  This flag has been introduced in version   */
+    /* 1.5 of the OpenType specification (May 2008).                 */
 
-    face->root.style_name = tt_face_get_name( face,
-                                              TT_NAME_ID_PREFERRED_SUBFAMILY );
-    if ( !face->root.style_name )
-      face->root.style_name  = tt_face_get_name( face,
-                                                 TT_NAME_ID_FONT_SUBFAMILY );
+    face->root.family_name = NULL;
+    face->root.style_name  = NULL;
+    if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 )
+    {
+      if ( !ignore_preferred_family )
+        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
+      if ( !face->root.family_name )
+        GET_NAME( FONT_FAMILY, &face->root.family_name );
+
+      if ( !ignore_preferred_subfamily )
+        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
+      if ( !face->root.style_name )
+        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
+    }
+    else
+    {
+      GET_NAME( WWS_FAMILY, &face->root.family_name );
+      if ( !face->root.family_name && !ignore_preferred_family )
+        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
+      if ( !face->root.family_name )
+        GET_NAME( FONT_FAMILY, &face->root.family_name );
+
+      GET_NAME( WWS_SUBFAMILY, &face->root.style_name );
+      if ( !face->root.style_name && !ignore_preferred_subfamily )
+        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
+      if ( !face->root.style_name )
+        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
+    }
 
     /* now set up root fields */
     {
-      FT_Face    root = &face->root;
-      FT_Int32   flags = root->face_flags;
+      FT_Face  root  = &face->root;
+      FT_Long  flags = root->face_flags;
 
 
       /*********************************************************************/
                FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
 
 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
-      if ( psnames_error == SFNT_Err_Ok &&
+      if ( psnames_error == SFNT_Err_Ok               &&
            face->postscript.FormatType != 0x00030000L )
         flags |= FT_FACE_FLAG_GLYPH_NAMES;
 #endif
       /*                                                                   */
       /* Compute style flags.                                              */
       /*                                                                   */
+
       flags = 0;
       if ( has_outline == TRUE && face->os2.version != 0xFFFFU )
       {
-        /* we have an OS/2 table; use the `fsSelection' field */
-        if ( face->os2.fsSelection & 1 )
+        /* We have an OS/2 table; use the `fsSelection' field.  Bit 9 */
+        /* indicates an oblique font face.  This flag has been        */
+        /* introduced in version 1.5 of the OpenType specification.   */
+
+        if ( face->os2.fsSelection & 512 )       /* bit 9 */
+          flags |= FT_STYLE_FLAG_ITALIC;
+        else if ( face->os2.fsSelection & 1 )    /* bit 0 */
           flags |= FT_STYLE_FLAG_ITALIC;
 
-        if ( face->os2.fsSelection & 32 )
+        if ( face->os2.fsSelection & 32 )        /* bit 5 */
           flags |= FT_STYLE_FLAG_BOLD;
       }
       else
       {
         /* this is an old Mac font, use the header field */
+
         if ( face->header.Mac_Style & 1 )
           flags |= FT_STYLE_FLAG_BOLD;
 
         }
       }
 
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+      /*
+       *  Now allocate the root array of FT_Bitmap_Size records and
+       *  populate them.  Unfortunately, it isn't possible to indicate bit
+       *  depths in the FT_Bitmap_Size record.  This is a design error.
+       */
+      {
+        FT_UInt  i, count;
+
+
+#ifndef FT_CONFIG_OPTION_OLD_INTERNALS
+        count = face->sbit_num_strikes;
+#else
+        count = (FT_UInt)face->num_sbit_strikes;
+#endif
+
+        if ( count > 0 )
+        {
+          FT_Memory        memory   = face->root.stream->memory;
+          FT_UShort        em_size  = face->header.Units_Per_EM;
+          FT_Short         avgwidth = face->os2.xAvgCharWidth;
+          FT_Size_Metrics  metrics;
+
+
+          if ( em_size == 0 || face->os2.version == 0xFFFFU )
+          {
+            avgwidth = 0;
+            em_size = 1;
+          }
+
+          if ( FT_NEW_ARRAY( root->available_sizes, count ) )
+            goto Exit;
+
+          for ( i = 0; i < count; i++ )
+          {
+            FT_Bitmap_Size*  bsize = root->available_sizes + i;
+
+
+            error = sfnt->load_strike_metrics( face, i, &metrics );
+            if ( error )
+              goto Exit;
+
+            bsize->height = (FT_Short)( metrics.height >> 6 );
+            bsize->width = (FT_Short)(
+                ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size );
+
+            bsize->x_ppem = metrics.x_ppem << 6;
+            bsize->y_ppem = metrics.y_ppem << 6;
+
+            /* assume 72dpi */
+            bsize->size   = metrics.y_ppem << 6;
+          }
+
+          root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
+          root->num_fixed_sizes = (FT_Int)count;
+        }
+      }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+      /* a font with no bitmaps and no outlines is scalable; */
+      /* it has only empty glyphs then                       */
+      if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) )
+        root->face_flags |= FT_FACE_FLAG_SCALABLE;
+
 
       /*********************************************************************/
       /*                                                                   */
       /*  Set up metrics.                                                  */
       /*                                                                   */
-      if ( has_outline == TRUE )
+      if ( FT_IS_SCALABLE( root ) )
       {
         /* XXX What about if outline header is missing */
         /*     (e.g. sfnt wrapped bitmap)?             */
         /* this computation is based on various versions of Times New Roman */
         if ( face->horizontal.Line_Gap == 0 )
           root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
-#endif
+#endif /* 0 */
 
 #if 0
-
         /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
         /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF             */
         if ( face->os2.version != 0xFFFFU && root->ascender )
           if ( height > root->height )
             root->height = height;
         }
-
 #endif /* 0 */
 
-        root->max_advance_width   = face->horizontal.advance_Width_Max;
-
-        root->max_advance_height  = (FT_Short)( face->vertical_info
-                                      ? face->vertical.advance_Height_Max
-                                      : root->height );
+        root->max_advance_width  = face->horizontal.advance_Width_Max;
+        root->max_advance_height = (FT_Short)( face->vertical_info
+                                     ? face->vertical.advance_Height_Max
+                                     : root->height );
 
-        root->underline_position  = face->postscript.underlinePosition;
+        /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */
+        /* Adjust underline position from top edge to centre of     */
+        /* stroke to convert TrueType meaning to FreeType meaning.  */
+        root->underline_position  = face->postscript.underlinePosition -
+                                    face->postscript.underlineThickness / 2;
         root->underline_thickness = face->postscript.underlineThickness;
       }
 
-#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-
-      /*
-       *  Now allocate the root array of FT_Bitmap_Size records and
-       *  populate them.  Unfortunately, it isn't possible to indicate bit
-       *  depths in the FT_Bitmap_Size record.  This is a design error.
-       */
-      {
-        FT_UInt  i, count;
-
-
-#if !defined FT_CONFIG_OPTION_OLD_INTERNALS
-        count = face->sbit_num_strikes;
-#else
-        count = (FT_UInt)face->num_sbit_strikes;
-#endif
-
-        if ( count > 0 )
-        {
-          FT_Memory        memory   = face->root.stream->memory;
-          FT_UShort        em_size  = face->header.Units_Per_EM;
-          FT_Short         avgwidth = face->os2.xAvgCharWidth;
-          FT_Size_Metrics  metrics;
-
-
-          if ( em_size == 0 || face->os2.version == 0xFFFFU )
-          {
-            avgwidth = 0;
-            em_size = 1;
-          }
-
-          if ( FT_NEW_ARRAY( root->available_sizes, count ) )
-            goto Exit;
-
-          for ( i = 0; i < count; i++ )
-          {
-            FT_Bitmap_Size*  bsize = root->available_sizes + i;
-
-
-            error = sfnt->load_strike_metrics( face, i, &metrics );
-            if ( error )
-              goto Exit;
-
-            bsize->height = (FT_Short)( metrics.height >> 6 );
-            bsize->width = (FT_Short)(
-                ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size );
-
-            bsize->x_ppem = metrics.x_ppem << 6;
-            bsize->y_ppem = metrics.y_ppem << 6;
-
-            /* assume 72dpi */
-            bsize->size   = metrics.y_ppem << 6;
-          }
-
-          root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
-          root->num_fixed_sizes = (FT_Int)count;
-        }
-      }
-
-#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
-
     }
 
   Exit:
 
 #undef LOAD_
 #undef LOADM_
+#undef GET_NAME
 
 
   FT_LOCAL_DEF( void )
   sfnt_done_face( TT_Face  face )
   {
-    FT_Memory     memory = face->root.memory;
-    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+    FT_Memory     memory;
+    SFNT_Service  sfnt;
+
 
+    if ( !face )
+      return;
+
+    memory = face->root.memory;
+    sfnt   = (SFNT_Service)face->sfnt;
 
     if ( sfnt )
     {
     }
 
     /* freeing the horizontal metrics */
-#if !defined FT_CONFIG_OPTION_OLD_INTERNALS
+#ifndef FT_CONFIG_OPTION_OLD_INTERNALS
     {
       FT_Stream  stream = FT_FACE_STREAM( face );
 
     face->gasp.numRanges = 0;
 
     /* freeing the name table */
-    sfnt->free_name( face );
+    if ( sfnt )
+      sfnt->free_name( face );
 
     /* freeing family and style name */
     FT_FREE( face->root.family_name );