[CMAKE]
[reactos.git] / lib / 3rdparty / freetype / src / truetype / ttobjs.c
index 0294a1b..8fe86ad 100644 (file)
@@ -4,7 +4,8 @@
 /*                                                                         */
 /*    Objects manager (body).                                              */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by             */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
+/*            2010 by                                                      */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -18,9 +19,7 @@
 
 #include <ft2build.h>
 #include FT_INTERNAL_DEBUG_H
-#include FT_INTERNAL_CALC_H
 #include FT_INTERNAL_STREAM_H
-#include FT_TRUETYPE_IDS_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_INTERNAL_SFNT_H
 
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
 
+  /* Compare the face with a list of well-known `tricky' fonts. */
+  /* This list shall be expanded as we find more of them.       */
+
+  static FT_Bool
+  tt_check_trickyness_family( FT_String*  name )
+  {
+
+#define TRICK_NAMES_MAX_CHARACTERS  16
+#define TRICK_NAMES_COUNT            8
+
+    static const char trick_names[TRICK_NAMES_COUNT]
+                                 [TRICK_NAMES_MAX_CHARACTERS + 1] =
+    {
+      "DFKaiSho-SB",     /* dfkaisb.ttf */
+      "DFKaiShu",
+      "DFKai-SB",        /* kaiu.ttf */
+      "HuaTianKaiTi?",   /* htkt2.ttf */
+      "HuaTianSongTi?",  /* htst3.ttf */
+      "MingLiU",         /* mingliu.ttf & mingliu.ttc */
+      "PMingLiU",        /* mingliu.ttc */
+      "MingLi43",        /* mingli.ttf */
+    };
+
+    int  nn;
+
+
+    for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ )
+      if ( ft_strstr( name, trick_names[nn] ) )
+        return TRUE;
+
+    return FALSE;
+  }
+
+
+  /* XXX: This function should be in the `sfnt' module. */
+
+  /* Some PDF generators clear the checksums in the TrueType header table. */
+  /* For example, Quartz ContextPDF clears all entries, or Bullzip PDF     */
+  /* Printer clears the entries for subsetted subtables.  We thus have to  */
+  /* recalculate the checksums  where necessary.                           */
+
+  static FT_UInt32
+  tt_synth_sfnt_checksum( FT_Stream  stream,
+                          FT_ULong   length )
+  {
+    FT_Error   error;
+    FT_UInt32  checksum = 0;
+    int        i;
+
+
+    if ( FT_FRAME_ENTER( length ) )
+      return 0;
+
+    for ( ; length > 3; length -= 4 )
+      checksum += (FT_UInt32)FT_GET_ULONG();
+
+    for ( i = 3; length > 0; length --, i-- )
+      checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) );
+
+    FT_FRAME_EXIT();
+
+    return checksum;
+  }
+
+
+  /* XXX: This function should be in the `sfnt' module. */
+
+  static FT_ULong
+  tt_get_sfnt_checksum( TT_Face    face,
+                        FT_UShort  i )
+  {
+    if ( face->dir_tables[i].CheckSum )
+      return face->dir_tables[i].CheckSum;
+
+    else if ( !face->goto_table )
+      return 0;
+
+    else if ( !face->goto_table( face,
+                                 face->dir_tables[i].Tag,
+                                 face->root.stream,
+                                 NULL ) )
+      return 0;
+
+    return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream,
+                                             face->dir_tables[i].Length );
+  }
+
+
+  typedef struct tt_sfnt_id_rec_
+  {
+    FT_ULong  CheckSum;
+    FT_ULong  Length;
+
+  } tt_sfnt_id_rec;
+
+
+  static FT_Bool
+  tt_check_trickyness_sfnt_ids( TT_Face  face )
+  {
+#define TRICK_SFNT_IDS_PER_FACE   3
+#define TRICK_SFNT_IDS_NUM_FACES  5
+
+    static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
+                                       [TRICK_SFNT_IDS_PER_FACE] = {
+
+#define TRICK_SFNT_ID_cvt   0
+#define TRICK_SFNT_ID_fpgm  1
+#define TRICK_SFNT_ID_prep  2
+
+      { /* MingLiU 1995 */
+        { 0x05bcf058, 0x000002e4 }, /* cvt  */
+        { 0x28233bf1, 0x000087c4 }, /* fpgm */
+        { 0xa344a1ea, 0x000001e1 }  /* prep */
+      },
+      { /* MingLiU 1996- */
+        { 0x05bcf058, 0x000002e4 }, /* cvt  */
+        { 0x28233bf1, 0x000087c4 }, /* fpgm */
+        { 0xa344a1eb, 0x000001e1 }  /* prep */
+      },
+      { /* DFKaiShu */
+        { 0x11e5ead4, 0x00000350 }, /* cvt  */
+        { 0x5a30ca3b, 0x00009063 }, /* fpgm */
+        { 0x13a42602, 0x0000007e }  /* prep */
+      },
+      { /* HuaTianKaiTi */
+        { 0xfffbfffc, 0x00000008 }, /* cvt  */
+        { 0x9c9e48b8, 0x0000bea2 }, /* fpgm */
+        { 0x70020112, 0x00000008 }  /* prep */
+      },
+      { /* HuaTianSongTi */
+        { 0xfffbfffc, 0x00000008 }, /* cvt  */
+        { 0x0a5a0483, 0x00017c39 }, /* fpgm */
+        { 0x70020112, 0x00000008 }  /* prep */
+      }
+    };
+
+    FT_ULong  checksum;
+    int       num_matched_ids[TRICK_SFNT_IDS_NUM_FACES];
+    int       i, j, k;
+
+
+    FT_MEM_SET( num_matched_ids, 0,
+                sizeof( int ) * TRICK_SFNT_IDS_NUM_FACES );
+
+    for ( i = 0; i < face->num_tables; i++ )
+    {
+      checksum = 0;
+
+      switch( face->dir_tables[i].Tag )
+      {
+      case TTAG_cvt:
+        k = TRICK_SFNT_ID_cvt;
+        break;
+
+      case TTAG_fpgm:
+        k = TRICK_SFNT_ID_fpgm;
+        break;
+
+      case TTAG_prep:
+        k = TRICK_SFNT_ID_prep;
+        break;
+
+      default:
+        continue;
+      }
+
+      for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ )
+        if ( face->dir_tables[i].Length == sfnt_id[j][k].Length )
+        {
+          if ( !checksum )
+            checksum = tt_get_sfnt_checksum( face, i );
+
+          if ( sfnt_id[j][k].CheckSum == checksum )
+            num_matched_ids[j]++;
+
+          if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE )
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+  }
+
+
+  static FT_Bool
+  tt_check_trickyness( FT_Face  face )
+  {
+    if ( !face )
+      return FALSE;
+
+    /* First, check the face name. */
+    if ( face->family_name )
+    {
+      if ( tt_check_trickyness_family( face->family_name ) )
+        return TRUE;
+      else
+        return FALSE;
+    }
+
+    /* Type42 fonts may lack `name' tables, we thus try to identify */
+    /* tricky fonts by checking the checksums of Type42-persistent  */
+    /* sfnt tables (`cvt', `fpgm', and `prep').                     */
+    if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) )
+      return TRUE;
+
+    return FALSE;
+  }
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
     TT_Face       face = (TT_Face)ttface;
 
 
-    library = face->root.driver->root.library;
+    library = ttface->driver->root.library;
     sfnt    = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
     if ( !sfnt )
       goto Bad_Format;
     }
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    face->root.face_flags |= FT_FACE_FLAG_HINTER;
+    ttface->face_flags |= FT_FACE_FLAG_HINTER;
 #endif
 
     /* If we are performing a simple font format check, exit immediately. */
     if ( error )
       goto Exit;
 
+    if ( tt_check_trickyness( ttface ) )
+      ttface->face_flags |= FT_FACE_FLAG_TRICKY;
+
     error = tt_face_load_hdmx( face, stream );
     if ( error )
       goto Exit;
 
-    if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE )
+    if ( FT_IS_SCALABLE( ttface ) )
     {
 
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
 
-      if ( !face->root.internal->incremental_interface )
+      if ( !ttface->internal->incremental_interface )
         error = tt_face_load_loca( face, stream );
       if ( !error )
-        error = tt_face_load_cvt( face, stream )  ||
-                tt_face_load_fpgm( face, stream ) ||
-                tt_face_load_prep( face, stream );
+        error = tt_face_load_cvt( face, stream );
+      if ( !error )
+        error = tt_face_load_fpgm( face, stream );
+      if ( !error )
+        error = tt_face_load_prep( face, stream );
 
 #else
 
       if ( !error )
-        error = tt_face_load_loca( face, stream ) ||
-                tt_face_load_cvt( face, stream )  ||
-                tt_face_load_fpgm( face, stream ) ||
-                tt_face_load_prep( face, stream );
+        error = tt_face_load_loca( face, stream );
+      if ( !error )
+        error = tt_face_load_cvt( face, stream );
+      if ( !error )
+        error = tt_face_load_fpgm( face, stream );
+      if ( !error )
+        error = tt_face_load_prep( face, stream );
 
 #endif
 
         if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING )
           unpatented_hinting = TRUE;
 
-      /* Compare the face with a list of well-known `tricky' fonts. */
-      /* This list shall be expanded as we find more of them.       */
       if ( !unpatented_hinting )
-      {
-        static const char* const  trick_names[] =
-        {
-          "DFKaiSho-SB",     /* dfkaisb.ttf */
-          "DFKai-SB",        /* kaiu.ttf */
-          "HuaTianSongTi?",  /* htst3.ttf */
-          "MingLiU",         /* mingliu.ttf & mingliu.ttc */
-          "PMingLiU",        /* mingliu.ttc */
-          "MingLi43",        /* mingli.ttf */
-          NULL
-        };
-        int  nn;
-
-
-        /* Note that we only check the face name at the moment; it might */
-        /* be worth to do more checks for a few special cases.           */
-        for ( nn = 0; trick_names[nn] != NULL; nn++ )
-        {
-          if ( ttface->family_name                               &&
-               ft_strstr( ttface->family_name, trick_names[nn] ) )
-          {
-            unpatented_hinting = 1;
-            break;
-          }
-        }
-      }
-
-      ttface->internal->ignore_unpatented_hinter =
-        FT_BOOL( !unpatented_hinting );
+        ttface->internal->ignore_unpatented_hinter = TRUE;
     }
 
 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING &&
   FT_LOCAL_DEF( void )
   tt_face_done( FT_Face  ttface )           /* TT_Face */
   {
-    TT_Face       face   = (TT_Face)ttface;
-    FT_Memory     memory = face->root.memory;
-    FT_Stream     stream = face->root.stream;
+    TT_Face       face = (TT_Face)ttface;
+    FT_Memory     memory;
+    FT_Stream     stream;
+    SFNT_Service  sfnt;
 
-    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
 
+    if ( !face )
+      return;
+
+    memory = ttface->memory;
+    stream = ttface->stream;
+    sfnt   = (SFNT_Service)face->sfnt;
 
     /* for `extended TrueType formats' (i.e. compressed versions) */
     if ( face->extra.finalizer )
       error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 );
 
       if ( !error )
+      {
+        FT_TRACE4(( "Executing `fpgm' table.\n" ));
+
         error = face->interpreter( exec );
+      }
     }
     else
       error = TT_Err_Ok;
       error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 );
 
       if ( !error && !size->debug )
+      {
+        FT_TRACE4(( "Executing `prep' table.\n" ));
+
         error = face->interpreter( exec );
+      }
     }
     else
       error = TT_Err_Ok;
 
     /* Set default metrics */
     {
-      FT_Size_Metrics*  metrics  = &size->metrics;
-      TT_Size_Metrics*  metrics2 = &size->ttmetrics;
+      TT_Size_Metrics*  metrics = &size->ttmetrics;
 
-      metrics->x_ppem = 0;
-      metrics->y_ppem = 0;
 
-      metrics2->rotated   = FALSE;
-      metrics2->stretched = FALSE;
+      metrics->rotated   = FALSE;
+      metrics->stretched = FALSE;
 
       /* set default compensation (all 0) */
       for ( i = 0; i < 4; i++ )
-        metrics2->compensations[i] = 0;
+        metrics->compensations[i] = 0;
     }
 
     /* allocate function defs, instruction defs, cvt, and storage area */
     if ( !size->cvt_ready )
     {
       FT_UInt  i;
-      TT_Face  face = (TT_Face) size->root.face;
+      TT_Face  face = (TT_Face)size->root.face;
 
 
       /* Scale the cvt values to the new ppem.          */
 
       error = tt_size_run_prep( size );
       if ( !error )
-          size->cvt_ready = 1;
+        size->cvt_ready = 1;
     }
+
   Exit:
     return error;
   }