Commit e706798d43da47cea09d1372db88aa16b3f06f5f

Werner Lemberg 2017-02-20T09:15:13

[cff] Finish support for `random' operator. * src/cff/cfftypes.h (CFF_SubFontRec): Add `random' field. * src/cff/cffobjs.c: Updated. (cff_driver_init): Initialize random seed value. * src/cff/cffload.c (cff_random): New function. (cff_subfont_load): Add `face' argument. Update all callers. Initialize random number generator with a proper seed value. (cff_font_load): Add `face' argument. Update all callers. * src/cff/cffload.h: Updated. * src/cff/cf2intrp.c (CF2_FIXME): Removed. (cf2_interpT2CharString) <cf2_escRANDOM>: Implement opcode. * src/cff/cffgload.c (cff_decoder_parse_charstrings): Don't initialize random seed value. <cff_op_random>: Use new random seed framework.

diff --git a/ChangeLog b/ChangeLog
index cb2b776..95873ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,30 @@
 2017-02-20  Werner Lemberg  <wl@gnu.org>
 
+	[cff] Finish support for `random' operator.
+
+	* src/cff/cfftypes.h (CFF_SubFontRec): Add `random' field.
+
+	* src/cff/cffobjs.c: Updated.
+	(cff_driver_init): Initialize random seed value.
+
+	* src/cff/cffload.c (cff_random): New function.
+	(cff_subfont_load): Add `face' argument.
+	Update all callers.
+	Initialize random number generator with a proper seed value.
+	(cff_font_load): Add `face' argument.
+	Update all callers.
+
+	* src/cff/cffload.h: Updated.
+
+	* src/cff/cf2intrp.c (CF2_FIXME): Removed.
+	(cf2_interpT2CharString) <cf2_escRANDOM>: Implement opcode.
+
+	* src/cff/cffgload.c (cff_decoder_parse_charstrings): Don't
+	initialize random seed value.
+	<cff_op_random>: Use new random seed framework.
+
+2017-02-20  Werner Lemberg  <wl@gnu.org>
+
 	[cff] Sanitize `initialRandomSeed'.
 
 	* src/cff/cffload.c (cff_load_private_dict): Make
diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c
index 6bf298a..62c696d 100644
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -60,12 +60,6 @@
 #define FT_COMPONENT  trace_cf2interp
 
 
-  /* some operators are not implemented yet */
-#define CF2_FIXME  FT_TRACE4(( "cf2_interpT2CharString:"            \
-                               " operator not implemented yet\n" ))
-
-
-
   FT_LOCAL_DEF( void )
   cf2_hintmask_init( CF2_HintMask  hintmask,
                      FT_Error*     error )
@@ -1268,10 +1262,23 @@
                   continue; /* do not clear the stack */
 
                 case cf2_escRANDOM: /* in spec */
-                  FT_TRACE4(( " random\n" ));
+                  {
+                    CF2_F16Dot16  r;
 
-                  CF2_FIXME;
-                  break;
+
+                    FT_TRACE4(( " random\n" ));
+
+                    /* only use the lower 16 bits of `random'  */
+                    /* to generate a number in the range (0;1] */
+                    r = (CF2_F16Dot16)
+                          ( ( decoder->current_subfont->random & 0xFFFF ) + 1 );
+
+                    decoder->current_subfont->random =
+                      cff_random( decoder->current_subfont->random );
+
+                    cf2_stack_pushFixed( opStack, r );
+                  }
+                  continue; /* do not clear the stack */
 
                 case cf2_escMUL:
                   {
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index f8e80c1..4803b4b 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -457,7 +457,7 @@
     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 */
+    decoder->current_subfont = sub;
 
   Exit:
     return error;
@@ -913,7 +913,6 @@
     FT_Byte*           limit;
     CFF_Builder*       builder = &decoder->builder;
     FT_Pos             x, y;
-    FT_Fixed           seed;
     FT_Fixed*          stack;
     FT_Int             charstring_type =
                          decoder->cff->top_font.font_dict.charstring_type;
@@ -929,15 +928,6 @@
     decoder->num_hints  = 0;
     decoder->read_width = 1;
 
-    /* compute random seed from stack address of parameter */
-    seed = (FT_Fixed)( ( (FT_Offset)(char*)&seed            ^
-                         (FT_Offset)(char*)&decoder         ^
-                         (FT_Offset)(char*)&charstring_base ) &
-                         FT_ULONG_MAX                         );
-    seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
-    if ( seed == 0 )
-      seed = 0x7384;
-
     /* initialize the decoder */
     decoder->top  = decoder->stack;
     decoder->zone = decoder->zones;
@@ -2104,22 +2094,16 @@
           break;
 
         case cff_op_random:
-          {
-            FT_Fixed  Rand;
-
-
-            FT_TRACE4(( " rand\n" ));
+          FT_TRACE4(( " random\n" ));
 
-            Rand = seed;
-            if ( Rand >= 0x8000L )
-              Rand++;
+          /* only use the lower 16 bits of `random'  */
+          /* to generate a number in the range (0;1] */
+          args[0] = (FT_Fixed)
+                      ( ( decoder->current_subfont->random & 0xFFFF ) + 1 );
+          args++;
 
-            args[0] = Rand;
-            seed    = FT_MulFix( seed, 0x10000L - seed );
-            if ( seed == 0 )
-              seed += 0x2873;
-            args++;
-          }
+          decoder->current_subfont->random =
+            cff_random( decoder->current_subfont->random );
           break;
 
         case cff_op_mul:
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index 9122ff9..47626a7 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -1931,6 +1931,18 @@
   }
 
 
+  FT_LOCAL_DEF( FT_UInt32 )
+  cff_random( FT_UInt32  r )
+  {
+    /* a 32bit version of the `xorshift' algorithm */
+    r ^= r << 13;
+    r ^= r >> 17;
+    r ^= r << 5;
+
+    return r;
+  }
+
+
   /* There are 3 ways to call this function, distinguished by code.  */
   /*                                                                 */
   /* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */
@@ -1944,7 +1956,8 @@
                     FT_Stream    stream,
                     FT_ULong     base_offset,
                     FT_UInt      code,
-                    CFF_Font     font )
+                    CFF_Font     font,
+                    CFF_Face     face )
   {
     FT_Error         error;
     CFF_ParserRec    parser;
@@ -2041,6 +2054,54 @@
     if ( error )
       goto Exit;
 
+    if ( !cff2 )
+    {
+      /*
+       * Initialize the random number generator.
+       *
+       * . If we have a face-specific seed, use it.
+       *   If non-zero, update it to a positive value.
+       *
+       * . Otherwise, use the seed from the CFF driver.
+       *   If non-zero, update it to a positive value.
+       *
+       * . If the random value is zero, use the seed given by the subfont's
+       *   `initialRandomSeed' value.
+       *
+       */
+      if ( face->root.internal->random_seed == -1 )
+      {
+        CFF_Driver  driver = (CFF_Driver)FT_FACE_DRIVER( face );
+
+
+        subfont->random = (FT_UInt32)driver->random_seed;
+        if ( driver->random_seed )
+        {
+          do
+          {
+            driver->random_seed = (FT_Int32)cff_random( driver->random_seed );
+
+          } while ( driver->random_seed < 0 );
+        }
+      }
+      else
+      {
+        subfont->random = (FT_UInt32)face->root.internal->random_seed;
+        if ( face->root.internal->random_seed )
+        {
+          do
+          {
+            face->root.internal->random_seed =
+              (FT_Int32)cff_random( face->root.internal->random_seed );
+
+          } while ( face->root.internal->random_seed < 0 );
+        }
+      }
+
+      if ( !subfont->random )
+        subfont->random = (FT_UInt32)priv->initial_random_seed;
+    }
+
     /* read the local subrs, if any */
     if ( priv->local_subrs_offset )
     {
@@ -2086,6 +2147,7 @@
                  FT_Stream  stream,
                  FT_Int     face_index,
                  CFF_Font   font,
+                 CFF_Face   face,
                  FT_Bool    pure_cff,
                  FT_Bool    cff2 )
   {
@@ -2283,7 +2345,8 @@
                               stream,
                               base_offset,
                               cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
-                              font );
+                              font,
+                              face );
     if ( error )
       goto Exit;
 
@@ -2350,7 +2413,8 @@
                                   base_offset,
                                   cff2 ? CFF2_CODE_FONTDICT
                                        : CFF_CODE_TOPDICT,
-                                  font );
+                                  font,
+                                  face );
         if ( error )
           goto Fail_CID;
       }
diff --git a/src/cff/cffload.h b/src/cff/cffload.h
index 8be6452..1709a66 100644
--- a/src/cff/cffload.h
+++ b/src/cff/cffload.h
@@ -61,11 +61,15 @@ FT_BEGIN_HEADER
                              FT_UInt      cid );
 
 
+  FT_LOCAL( FT_UInt32 )
+  cff_random( FT_UInt32  r );
+
   FT_LOCAL( FT_Error )
   cff_font_load( FT_Library  library,
                  FT_Stream   stream,
                  FT_Int      face_index,
                  CFF_Font    font,
+                 CFF_Face    face,
                  FT_Bool     pure_cff,
                  FT_Bool     cff2 );
 
diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c
index f0320af..67bf0cc 100644
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -595,6 +595,7 @@
                              stream,
                              face_index,
                              cff,
+                             face,
                              pure_cff,
                              cff2 );
       if ( error )
@@ -1157,6 +1158,8 @@
   {
     CFF_Driver  driver = (CFF_Driver)module;
 
+    FT_UInt32  seed;
+
 
     /* set default property values, cf. `ftcffdrv.h' */
 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
@@ -1176,6 +1179,18 @@
     driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
     driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
 
+    /* compute random seed from some memory addresses */
+    seed = (FT_UInt32)( (FT_Offset)(char*)&seed          ^
+                        (FT_Offset)(char*)&module        ^
+                        (FT_Offset)(char*)module->memory );
+    seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
+
+    driver->random_seed = (FT_Int32)seed;
+    if ( driver->random_seed < 0 )
+      driver->random_seed = -driver->random_seed;
+    else if ( driver->random_seed == 0 )
+      driver->random_seed = 123456789;
+
     return FT_Err_Ok;
   }
 
diff --git a/src/cff/cfftypes.h b/src/cff/cfftypes.h
index 0c24ed5..8d43e28 100644
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -321,6 +321,8 @@ FT_BEGIN_HEADER
     FT_Byte**     local_subrs; /* array of pointers           */
                                /* into Local Subrs INDEX data */
 
+    FT_UInt32  random;
+
   } CFF_SubFontRec;