Commit abe0d47265426740eca7e38aff0c5af98c6c936a

Tom Kacvinsky 2000-12-30T00:39:40

Added functions t2_lookup_glyph_by_stdcharcode and t2_operator_seac for use in implementing the seac emulation provided by the Type 2 endchar operator. Extended T2_Parse_CharStrings to add seac emulation for the endchar operator.

diff --git a/src/cff/t2gload.c b/src/cff/t2gload.c
index a934821..9dd83e3 100644
--- a/src/cff/t2gload.c
+++ b/src/cff/t2gload.c
@@ -513,6 +513,153 @@
       outline->contours[outline->n_contours - 1] = outline->n_points - 1;
   }
 
+  static
+  FT_Int  t2_lookup_glyph_by_stdcharcode( CFF_Font*  cff,
+                                          FT_Int     charcode )
+  {
+    FT_UInt    n;
+    FT_UShort  glyph_sid;
+
+    /* check range of standard char code */
+    if ( charcode < 0 || charcode > 255 )
+      return -1;
+
+
+    /* Get code to SID mapping from `cff_standard_encoding'. */
+    glyph_sid = cff_standard_encoding[charcode];
+
+    for ( n = 0; n < cff->num_glyphs; n++ )
+    {
+
+      if ( cff->charset.sids[n] == glyph_sid )
+        return n;
+    }
+
+    return -1;
+  }
+
+  static
+  FT_Error  t2_operator_seac( T2_Decoder*  decoder,
+                              FT_Pos       adx,
+                              FT_Pos       ady,
+                              FT_Int       bchar,
+                              FT_Int       achar )
+  {
+    FT_Error     error;
+    FT_Int       bchar_index, achar_index, n_base_points;
+    FT_Outline*  base = decoder->builder.base;
+    TT_Face      face = decoder->builder.face;
+    CFF_Font*    cff  = (CFF_Font*)(face->extra.data);
+    FT_Vector    left_bearing, advance;
+    FT_Byte*     charstring;
+    FT_ULong     charstring_len;
+
+    bchar_index = t2_lookup_glyph_by_stdcharcode( cff, bchar );
+    achar_index = t2_lookup_glyph_by_stdcharcode( cff, achar );
+
+    if ( bchar_index < 0 || achar_index < 0 )
+    {
+      FT_ERROR(( "t2_operator_seac:" ));
+      FT_ERROR(( " invalid seac character code arguments\n" ));
+      return T2_Err_Syntax_Error;
+    }
+
+    /* if we are trying to load a composite glyph, do not load the */
+    /* accent character and return the array of subglyphs.         */
+    if ( decoder->builder.no_recurse )
+    {
+      FT_GlyphSlot     glyph  = (FT_GlyphSlot)decoder->builder.glyph;
+      FT_GlyphLoader*  loader = glyph->internal->loader;
+      FT_SubGlyph*     subg;
+
+
+      /* reallocate subglyph array if necessary */
+      error = FT_GlyphLoader_Check_Subglyphs( loader, 2 );
+      if ( error )
+        goto Exit;
+
+      subg = loader->current.subglyphs;
+
+      /* subglyph 0 = base character */
+      subg->index = bchar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+                    FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+      subg->arg1  = 0;
+      subg->arg2  = 0;
+      subg++;
+
+      /* subglyph 1 = accent character */
+      subg->index = achar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+      subg->arg1  = adx;
+      subg->arg2  = ady;
+
+      /* set up remaining glyph fields */
+      glyph->num_subglyphs = 2;
+      glyph->subglyphs     = loader->base.subglyphs;
+      glyph->format        = ft_glyph_format_composite;
+
+      loader->current.num_subglyphs = 2;
+    }
+
+    /* First load `bchar' in builder */
+    error = CFF_Access_Element( &cff->charstrings_index, bchar_index,
+                                &charstring, &charstring_len );
+    if ( !error )
+    {
+
+      error = T2_Parse_CharStrings( decoder, charstring, charstring_len );
+
+      if ( error )
+        goto Exit;
+
+      CFF_Forget_Element( &cff->charstrings_index, &charstring );
+    }
+
+    n_base_points = base->n_points;
+
+    /* save the left bearing and width of the base character */
+    /* as they will be erased by the next load.              */
+
+    left_bearing = decoder->builder.left_bearing;
+    advance      = decoder->builder.advance;
+
+    decoder->builder.left_bearing.x = 0;
+    decoder->builder.left_bearing.y = 0;
+
+    /* Now load `achar' on top of the base outline           */
+    error = CFF_Access_Element( &cff->charstrings_index, achar_index,
+                                &charstring, &charstring_len );
+    if ( !error )
+    {
+
+      error = T2_Parse_CharStrings( decoder, charstring, charstring_len );
+
+      if ( error )
+        goto Exit;
+
+      CFF_Forget_Element( &cff->charstrings_index, &charstring );
+    }
+
+    /* restore the left side bearing and advance width of the base character */
+    decoder->builder.left_bearing = left_bearing;
+    decoder->builder.advance      = advance;
+
+    /* Finally, move the accent */
+    if ( decoder->builder.load_points )
+    {
+      FT_Outline  dummy;
+
+      dummy.n_points = base->n_points - n_base_points;
+      dummy.points   = base->points   + n_base_points;
+
+      FT_Outline_Translate( &dummy, adx, ady );
+    }
+
+  Exit:
+    return error;
+  }
+
 
   /*************************************************************************/
   /*                                                                       */
@@ -856,11 +1003,16 @@
             case t2_op_vstem:
             case t2_op_hstemhm:
             case t2_op_vstemhm:
-            case t2_op_endchar:
             case t2_op_rmoveto:
               set_width_ok = num_args & 1;
               break;
 
+            case t2_op_endchar:
+              /* If there is a width specified for endchar, we either have 1 */
+              /* argument or 5 arguments.  We like to argue.                 */
+              set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
+              break;
+
             default:
               set_width_ok = 0;
               break;
@@ -870,6 +1022,8 @@
             {
               decoder->glyph_width = decoder->nominal_width +
                                        ( stack[0] >> 16 );
+
+              /* Consumed an argument. */
               num_args--;
               args++;
             }
@@ -1424,6 +1578,18 @@
         case t2_op_endchar:
           FT_TRACE4(( " endchar" ));
 
+          /* We are going to emulate the seac operator. */
+          if ( num_args == 4)
+          {
+
+            error = t2_operator_seac( decoder, args[0] >> 16, args[1] >> 16,
+                                               args[2] >> 16, args[3] >> 16 );
+             args += 4;
+          }
+
+          if ( !error )
+            error = T2_Err_Ok;
+
           close_contour( builder );
 
           /* add current outline to the glyph slot */
@@ -1431,7 +1597,7 @@
 
           /* return now! */
           FT_TRACE4(( "\n\n" ));
-          return T2_Err_Ok;
+          return error;
 
         case t2_op_abs:
           FT_TRACE4(( " abs" ));