tizen 2.3.1 release
[framework/graphics/freetype.git] / src / cff / cffgload.c
index 84847fd..758a3d3 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    OpenType Glyph Loader (body).                                        */
 /*                                                                         */
-/*  Copyright 1996-2012 by                                                 */
+/*  Copyright 1996-2014 by                                                 */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
 #include FT_INTERNAL_STREAM_H
 #include FT_INTERNAL_SFNT_H
 #include FT_OUTLINE_H
+#include FT_CFF_DRIVER_H
 
 #include "cffobjs.h"
 #include "cffload.h"
 #include "cffgload.h"
+#include "cf2ft.h"      /* for cf2_decoder_parse_charstrings */
 
 #include "cfferrs.h"
 
@@ -39,6 +41,8 @@
 #define FT_COMPONENT  trace_cffgload
 
 
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+
   typedef enum  CFF_Operator_
   {
     cff_op_unknown = 0,
     2  /* setcurrentpoint */
   };
 
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
 
   /*************************************************************************/
   /*************************************************************************/
     CFF_Builder  *builder = &decoder->builder;
     CFF_Font      cff     = (CFF_Font)builder->face->extra.data;
     CFF_SubFont   sub     = &cff->top_font;
-    FT_Error      error   = CFF_Err_Ok;
+    FT_Error      error   = FT_Err_Ok;
 
 
     /* manage CID fonts */
       if ( fd_index >= cff->num_subfonts )
       {
         FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" ));
-        error = CFF_Err_Invalid_File_Format;
+        error = FT_THROW( Invalid_File_Format );
         goto Exit;
       }
 
-      FT_TRACE3(( "glyph index %d (subfont %d):\n", glyph_index, fd_index ));
+      FT_TRACE3(( "  in subfont %d:\n", fd_index ));
 
       sub = cff->subfonts[fd_index];
 
         builder->hints_globals = (void *)internal->subfonts[fd_index];
       }
     }
-#ifdef FT_DEBUG_LEVEL_TRACE
-    else
-      FT_TRACE3(( "glyph index %d:\n", glyph_index ));
-#endif
 
     decoder->num_locals    = sub->local_subrs_index.count;
     decoder->locals        = sub->local_subrs;
     decoder->glyph_width   = sub->private_dict.default_width;
     decoder->nominal_width = sub->private_dict.nominal_width;
 
+    decoder->current_subfont = sub;     /* for Adobe's CFF handler */
+
   Exit:
     return error;
   }
 
 
   /* check that there is enough space for `count' more points */
-  static FT_Error
-  check_points( CFF_Builder*  builder,
-                FT_Int        count )
+  FT_LOCAL_DEF( FT_Error )
+  cff_check_points( CFF_Builder*  builder,
+                    FT_Int        count )
   {
     return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
   }
 
 
   /* add a new point, do not check space */
-  static void
+  FT_LOCAL_DEF( void )
   cff_builder_add_point( CFF_Builder*  builder,
                          FT_Pos        x,
                          FT_Pos        y,
       FT_Vector*  point   = outline->points + outline->n_points;
       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
 
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+      CFF_Driver  driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
+
 
-      point->x = x >> 16;
-      point->y = y >> 16;
+      if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
+      {
+        point->x = x >> 16;
+        point->y = y >> 16;
+      }
+      else
+#endif
+      {
+        /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
+        point->x = x >> 10;
+        point->y = y >> 10;
+      }
       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
     }
 
 
 
   /* check space for a new on-curve point, then add it */
-  static FT_Error
+  FT_LOCAL_DEF( FT_Error )
   cff_builder_add_point1( CFF_Builder*  builder,
                           FT_Pos        x,
                           FT_Pos        y )
     FT_Error  error;
 
 
-    error = check_points( builder, 1 );
+    error = cff_check_points( builder, 1 );
     if ( !error )
       cff_builder_add_point( builder, x, y, 1 );
 
     if ( !builder->load_points )
     {
       outline->n_contours++;
-      return CFF_Err_Ok;
+      return FT_Err_Ok;
     }
 
     error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
 
 
   /* if a path was begun, add its first on-curve point */
-  static FT_Error
+  FT_LOCAL_DEF( FT_Error )
   cff_builder_start_point( CFF_Builder*  builder,
                            FT_Pos        x,
                            FT_Pos        y )
   {
-    FT_Error  error = CFF_Err_Ok;
+    FT_Error  error = FT_Err_Ok;
 
 
     /* test whether we are building a new contour */
 
 
   /* close the current contour */
-  static void
+  FT_LOCAL_DEF( void )
   cff_builder_close_contour( CFF_Builder*  builder )
   {
     FT_Outline*  outline = builder->current;
   }
 
 
-  static FT_Int
+  FT_LOCAL_DEF( FT_Int )
   cff_lookup_glyph_by_stdcharcode( CFF_Font  cff,
                                    FT_Int    charcode )
   {
   }
 
 
-  static FT_Error
+  FT_LOCAL_DEF( FT_Error )
   cff_get_glyph_data( TT_Face    face,
                       FT_UInt    glyph_index,
                       FT_Byte**  pointer,
   }
 
 
-  static void
+  FT_LOCAL_DEF( void )
   cff_free_glyph_data( TT_Face    face,
                        FT_Byte**  pointer,
                        FT_ULong   length )
     /* callback function.                                     */
     if ( face->root.internal->incremental_interface )
     {
-      FT_Data data;
+      FT_Data  data;
 
 
       data.pointer = *pointer;
   }
 
 
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+
   static FT_Error
   cff_operator_seac( CFF_Decoder*  decoder,
                      FT_Pos        asb,
     if ( decoder->seac )
     {
       FT_ERROR(( "cff_operator_seac: invalid nested seac\n" ));
-      return CFF_Err_Syntax_Error;
+      return FT_THROW( Syntax_Error );
     }
 
     adx += decoder->builder.left_bearing.x;
     {
       FT_ERROR(( "cff_operator_seac:"
                  " invalid seac character code arguments\n" ));
-      return CFF_Err_Syntax_Error;
+      return FT_THROW( Syntax_Error );
     }
 
     /* If we are trying to load a composite glyph, do not load the */
     limit = zone->limit  = charstring_base + charstring_len;
     ip    = zone->cursor = zone->base;
 
-    error = CFF_Err_Ok;
+    error = FT_Err_Ok;
 
     x = builder->pos_x;
     y = builder->pos_y;
 
 
         /* this is an operand, push it on the stack */
+
+        /* if we use shifts, all computations are done with unsigned */
+        /* values; the conversion to a signed value is the last step */
         if ( v == 28 )
         {
           if ( ip + 1 >= limit )
             goto Syntax_Error;
-          val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
+          val = (FT_Short)( ( (FT_UShort)ip[0] << 8 ) | ip[1] );
           ip += 2;
         }
         else if ( v < 247 )
         {
           if ( ip + 3 >= limit )
             goto Syntax_Error;
-          val = ( (FT_Int32)ip[0] << 24 ) |
-                ( (FT_Int32)ip[1] << 16 ) |
-                ( (FT_Int32)ip[2] <<  8 ) |
-                            ip[3];
+          val = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) |
+                            ( (FT_UInt32)ip[1] << 16 ) |
+                            ( (FT_UInt32)ip[2] <<  8 ) |
+                              (FT_UInt32)ip[3]         );
           ip    += 4;
           if ( charstring_type == 2 )
             shift = 0;
         if ( decoder->top - stack >= CFF_MAX_OPERANDS )
           goto Stack_Overflow;
 
-        val           <<= shift;
+        val             = (FT_Int32)( (FT_UInt32)val << shift );
         *decoder->top++ = val;
 
 #ifdef FT_DEBUG_LEVEL_TRACE
         if ( !( val & 0xFFFFL ) )
-          FT_TRACE4(( " %ld", (FT_Int32)( val >> 16 ) ));
+          FT_TRACE4(( " %hd", (FT_Short)( (FT_UInt32)val >> 16 ) ));
         else
           FT_TRACE4(( " %.2f", val / 65536.0 ));
 #endif
         case cff_op_rlineto:
           FT_TRACE4(( " rlineto\n" ));
 
-          if ( cff_builder_start_point ( builder, x, y ) ||
-               check_points( builder, num_args / 2 )     )
+          if ( cff_builder_start_point( builder, x, y )  ||
+               cff_check_points( builder, num_args / 2 ) )
             goto Fail;
 
           if ( num_args < 2 )
             if ( num_args == 0 )
               break;
 
-            if ( cff_builder_start_point ( builder, x, y ) ||
-                 check_points( builder, num_args )         )
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 cff_check_points( builder, num_args )    )
               goto Fail;
 
             args = stack;
 
             nargs = num_args - num_args % 6;
 
-            if ( cff_builder_start_point ( builder, x, y ) ||
-                 check_points( builder, nargs / 2 )     )
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 cff_check_points( builder, nargs / 2 )   )
               goto Fail;
 
             args -= nargs;
               nargs--;
             }
 
-            if ( check_points( builder, 3 * ( nargs / 4 ) ) )
+            if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) )
               goto Fail;
 
             while ( args < decoder->top )
               nargs--;
             }
 
-            if ( check_points( builder, 3 * ( nargs / 4 ) ) )
+            if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) )
               goto Fail;
 
             while ( args < decoder->top )
             nargs = num_args & ~2;
 
             args -= nargs;
-            if ( check_points( builder, ( nargs / 4 ) * 3 ) )
+            if ( cff_check_points( builder, ( nargs / 4 ) * 3 ) )
               goto Stack_Underflow;
 
             phase = ( op == cff_op_hvcurveto );
             nargs     = num_args & ~1;
             num_lines = ( nargs - 6 ) / 2;
 
-            if ( cff_builder_start_point( builder, x, y ) ||
-                 check_points( builder, num_lines + 3 )   )
+            if ( cff_builder_start_point( builder, x, y )   ||
+                 cff_check_points( builder, num_lines + 3 ) )
               goto Fail;
 
             args -= nargs;
             nargs      = nargs - nargs % 6 + 2;
             num_curves = ( nargs - 2 ) / 6;
 
-            if ( cff_builder_start_point ( builder, x, y ) ||
-                 check_points( builder, num_curves * 3 + 2 ) )
+            if ( cff_builder_start_point( builder, x, y )        ||
+                 cff_check_points( builder, num_curves * 3 + 2 ) )
               goto Fail;
 
             args -= nargs;
             /* -- make sure we have enough space for the start point if it */
             /* needs to be added                                           */
             if ( cff_builder_start_point( builder, x, y ) ||
-                 check_points( builder, 6 )               )
+                 cff_check_points( builder, 6 )           )
               goto Fail;
 
             /* record the starting point's y position for later use */
 
             /* adding six more points; 4 control points, 2 on-curve points */
             if ( cff_builder_start_point( builder, x, y ) ||
-                 check_points( builder, 6 )               )
+                 cff_check_points( builder, 6 )           )
               goto Fail;
 
             /* record the starting point's y-position for later use */
 
             /* adding six more points; 4 control points, 2 on-curve points */
             if ( cff_builder_start_point( builder, x, y ) ||
-                 check_points( builder, 6 )               )
+                 cff_check_points( builder, 6 )           )
               goto Fail;
 
             /* record the starting point's x, y position for later use */
             FT_TRACE4(( " flex\n" ));
 
             if ( cff_builder_start_point( builder, x, y ) ||
-                 check_points( builder, 6 )               )
+                 cff_check_points( builder, 6 )           )
               goto Fail;
 
             for ( count = 6; count > 0; count-- )
           }
           else
           {
-            if ( !error )
-              error = CFF_Err_Ok;
-
             cff_builder_close_contour( builder );
 
             /* close hints recording session */
                 goto Syntax_Error;
 
               /* apply hints to the loaded glyph outline now */
-              hinter->apply( hinter->hints,
-                             builder->current,
-                             (PSH_Globals)builder->hints_globals,
-                             decoder->hint_mode );
+              error = hinter->apply( hinter->hints,
+                                     builder->current,
+                                     (PSH_Globals)builder->hints_globals,
+                                     decoder->hint_mode );
+              if ( error )
+                goto Fail;
             }
 
             /* add current outline to the glyph slot */
             FT_ERROR(( " %d", ip[0] ));
           FT_ERROR(( "\n" ));
 
-          return CFF_Err_Unimplemented_Feature;
+          return FT_THROW( Unimplemented_Feature );
         }
 
         decoder->top = args;
 
   Syntax_Error:
     FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" ));
-    return CFF_Err_Invalid_File_Format;
+    return FT_THROW( Invalid_File_Format );
 
   Stack_Underflow:
     FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" ));
-    return CFF_Err_Too_Few_Arguments;
+    return FT_THROW( Too_Few_Arguments );
 
   Stack_Overflow:
     FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" ));
-    return CFF_Err_Stack_Overflow;
+    return FT_THROW( Stack_Overflow );
   }
 
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
 
   /*************************************************************************/
   /*************************************************************************/
   cff_compute_max_advance( TT_Face  face,
                            FT_Int*  max_advance )
   {
-    FT_Error     error = CFF_Err_Ok;
+    FT_Error     error = FT_Err_Ok;
     CFF_Decoder  decoder;
     FT_Int       glyph_index;
     CFF_Font     cff = (CFF_Font)face->other;
       }
 
       /* ignore the error if one has occurred -- skip to next glyph */
-      error = CFF_Err_Ok;
+      error = FT_Err_Ok;
     }
 
     *max_advance = decoder.builder.advance.x;
 
-    return CFF_Err_Ok;
+    return FT_Err_Ok;
   }
 
 
     FT_Error     error;
     CFF_Decoder  decoder;
     TT_Face      face = (TT_Face)glyph->root.face;
-    FT_Bool      hinting, force_scaling;
+    FT_Bool      hinting, scaled, force_scaling;
     CFF_Font     cff  = (CFF_Font)face->extra.data;
 
     FT_Matrix    font_matrix;
         glyph_index = cff_charset_cid_to_gindex( &cff->charset,
                                                  glyph_index );
         if ( glyph_index == 0 )
-          return CFF_Err_Invalid_Argument;
+          return FT_THROW( Invalid_Argument );
       }
     }
     else if ( glyph_index >= cff->num_glyphs )
-      return CFF_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
     if ( load_flags & FT_LOAD_NO_RECURSE )
       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 
         if ( !error )
         {
+          FT_Bool    has_vertical_info;
+          FT_UShort  advance;
+          FT_Short   dummy;
+
+
           glyph->root.outline.n_points   = 0;
           glyph->root.outline.n_contours = 0;
 
             glyph->root.bitmap_left = metrics.horiBearingX;
             glyph->root.bitmap_top  = metrics.horiBearingY;
           }
+
+          /* compute linear advance widths */
+
+          (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
+                                                           glyph_index,
+                                                           &dummy,
+                                                           &advance );
+          glyph->root.linearHoriAdvance = advance;
+
+          has_vertical_info = FT_BOOL(
+                                face->vertical_info                   &&
+                                face->vertical.number_Of_VMetrics > 0 );
+
+          /* get the vertical metrics from the vtmx table if we have one */
+          if ( has_vertical_info )
+          {
+            (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+                                                             glyph_index,
+                                                             &dummy,
+                                                             &advance );
+            glyph->root.linearVertAdvance = advance;
+          }
+          else
+          {
+            /* make up vertical ones */
+            if ( face->os2.version != 0xFFFFU )
+              glyph->root.linearVertAdvance = (FT_Pos)
+                ( face->os2.sTypoAscender - face->os2.sTypoDescender );
+            else
+              glyph->root.linearVertAdvance = (FT_Pos)
+                ( face->horizontal.Ascender - face->horizontal.Descender );
+          }
+
           return error;
         }
       }
 
     /* return immediately if we only want the embedded bitmaps */
     if ( load_flags & FT_LOAD_SBITS_ONLY )
-      return CFF_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
     /* if we have a CID subfont, use its matrix (which has already */
     /* been multiplied with the root matrix)                       */
       FT_Byte   fd_index = cff_fd_select_get( &cff->fd_select,
                                               glyph_index );
 
+
       if ( fd_index >= cff->num_subfonts )
         fd_index = (FT_Byte)( cff->num_subfonts - 1 );
 
     glyph->root.outline.n_points   = 0;
     glyph->root.outline.n_contours = 0;
 
-    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
-                       ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+    /* top-level code ensures that FT_LOAD_NO_HINTING is set */
+    /* if FT_LOAD_NO_SCALE is active                         */
+    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+    scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
 
+    glyph->hint        = hinting;
+    glyph->scaled      = scaled;
     glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;  /* by default */
 
     {
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+      CFF_Driver  driver = (CFF_Driver)FT_FACE_DRIVER( face );
+#endif
+
+
       FT_Byte*  charstring;
       FT_ULong  charstring_len;
 
       if ( error )
         goto Glyph_Build_Finished;
 
-      error = cff_decoder_parse_charstrings( &decoder,
-                                             charstring,
-                                             charstring_len );
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+      /* choose which CFF renderer to use */
+      if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
+        error = cff_decoder_parse_charstrings( &decoder,
+                                               charstring,
+                                               charstring_len );
+      else
+#endif
+      {
+        error = cf2_decoder_parse_charstrings( &decoder,
+                                               charstring,
+                                               charstring_len );
+
+        /* Adobe's engine uses 16.16 numbers everywhere;              */
+        /* as a consequence, glyphs larger than 2000ppem get rejected */
+        if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
+        {
+          /* this time, we retry unhinted and scale up the glyph later on */
+          /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
+          /* 0x400 for both `x_scale' and `y_scale' in this case)         */
+          hinting       = FALSE;
+          force_scaling = TRUE;
+          glyph->hint   = hinting;
+
+          error = cf2_decoder_parse_charstrings( &decoder,
+                                                 charstring,
+                                                 charstring_len );
+        }
+      }
 
       cff_free_glyph_data( face, &charstring, charstring_len );
 
         glyph->root.linearHoriAdvance           = decoder.glyph_width;
         glyph->root.internal->glyph_transformed = 0;
 
-#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
-        has_vertical_info = FT_BOOL( face->vertical_info                   &&
-                                     face->vertical.number_Of_VMetrics > 0 &&
-                                     face->vertical.long_metrics           );
-#else
         has_vertical_info = FT_BOOL( face->vertical_info                   &&
                                      face->vertical.number_Of_VMetrics > 0 );
-#endif
 
         /* get the vertical metrics from the vtmx table if we have one */
         if ( has_vertical_info )
           FT_UShort  vertAdvance  = 0;
 
 
-          ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
-                                                     glyph_index,
-                                                     &vertBearingY,
-                                                     &vertAdvance );
+          (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+                                                           glyph_index,
+                                                           &vertBearingY,
+                                                           &vertAdvance );
           metrics->vertBearingY = vertBearingY;
           metrics->vertAdvance  = vertAdvance;
         }