shithub: freetype+ttf2subf

Download patch

ref: 950f16969e18307e7373fa3c64e51b1c44d0b754
parent: 1a95d002109231f7f2a62aee8a3abadb6e0bc1da
author: Werner Lemberg <[email protected]>
date: Sun Feb 7 06:39:54 EST 2016

[cff] Implement missing operators in new engine (except `random').

* src/cff/cf2font.h (CF2_STORAGE_SIZE): New macro.

* src/cff/cf2intrp.c (cf2_interpT2CharString): Implement the
following operators: abs, add, and, div, drop, dup, eq, exch, get,
ifelse, index, mul, neg, not, or, put, roll, sqrt, sub.

* src/cff/cf2stack.h, src/cff/cf2stack.c (cf2_stack_roll): New
auxiliary function for `roll' operator.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2016-02-07  Werner Lemberg  <[email protected]>
+
+	[cff] Implement missing operators in new engine (except `random').
+
+	* src/cff/cf2font.h (CF2_STORAGE_SIZE): New macro.
+
+	* src/cff/cf2intrp.c (cf2_interpT2CharString): Implement the
+	following operators: abs, add, and, div, drop, dup, eq, exch, get,
+	ifelse, index, mul, neg, not, or, put, roll, sqrt, sub.
+
+	* src/cff/cf2stack.h, src/cff/cf2stack.c (cf2_stack_roll): New
+	auxiliary function for `roll' operator.
+
 2016-02-06  Werner Lemberg  <[email protected]>
 
 	[cff] Fix some Type 2 operators in old CFF engine.
--- a/src/cff/cf2font.h
+++ b/src/cff/cf2font.h
@@ -54,6 +54,7 @@
                                    /* (Hiragino Kaku Gothic ProN W3;      */
                                    /* 8.2d6e1; 2014-12-19) that exceed    */
                                    /* this limit                          */
+#define CF2_STORAGE_SIZE        32
 
 
   /* typedef is in `cf2glue.h' */
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -447,6 +447,8 @@
     CF2_Stack  opStack = NULL;
     FT_Byte    op1;                       /* first opcode byte */
 
+    CF2_F16Dot16  storage[CF2_STORAGE_SIZE];    /* for `put' and `get' */
+
     /* instruction limit; 20,000,000 matches Avalon */
     FT_UInt32  instructionLimit = 20000000UL;
 
@@ -834,85 +836,190 @@
 
             break;
 
-          /* TODO: should these operators be supported? */
-          case cf2_escAND: /* in spec */
-            FT_TRACE4(( " and\n" ));
+          case cf2_escAND:
+            {
+              CF2_F16Dot16  arg1;
+              CF2_F16Dot16  arg2;
 
-            CF2_FIXME;
-            break;
 
-          case cf2_escOR: /* in spec */
-            FT_TRACE4(( " or\n" ));
+              FT_TRACE4(( " and\n" ));
 
-            CF2_FIXME;
-            break;
+              arg2 = cf2_stack_popFixed( opStack );
+              arg1 = cf2_stack_popFixed( opStack );
 
-          case cf2_escNOT: /* in spec */
-            FT_TRACE4(( " not\n" ));
+              cf2_stack_pushInt( opStack, arg1 && arg2 );
+            }
+            continue; /* do not clear the stack */
 
-            CF2_FIXME;
-            break;
+          case cf2_escOR:
+            {
+              CF2_F16Dot16  arg1;
+              CF2_F16Dot16  arg2;
 
-          case cf2_escABS: /* in spec */
-            FT_TRACE4(( " abs\n" ));
 
-            CF2_FIXME;
-            break;
+              FT_TRACE4(( " or\n" ));
 
-          case cf2_escADD: /* in spec */
-            FT_TRACE4(( " add\n" ));
+              arg2 = cf2_stack_popFixed( opStack );
+              arg1 = cf2_stack_popFixed( opStack );
 
-            CF2_FIXME;
-            break;
+              cf2_stack_pushInt( opStack, arg1 || arg2 );
+            }
+            continue; /* do not clear the stack */
 
-          case cf2_escSUB: /* in spec */
-            FT_TRACE4(( " sub\n" ));
+          case cf2_escNOT:
+            {
+              CF2_F16Dot16  arg;
 
-            CF2_FIXME;
-            break;
 
-          case cf2_escDIV: /* in spec */
-            FT_TRACE4(( " div\n" ));
+              FT_TRACE4(( " not\n" ));
 
-            CF2_FIXME;
-            break;
+              arg = cf2_stack_popFixed( opStack );
 
-          case cf2_escNEG: /* in spec */
-            FT_TRACE4(( " neg\n" ));
+              cf2_stack_pushInt( opStack, !arg );
+            }
+            continue; /* do not clear the stack */
 
-            CF2_FIXME;
-            break;
+          case cf2_escABS:
+            {
+              CF2_F16Dot16  arg;
 
-          case cf2_escEQ: /* in spec */
-            FT_TRACE4(( " eq\n" ));
 
-            CF2_FIXME;
-            break;
+              FT_TRACE4(( " abs\n" ));
 
-          case cf2_escDROP: /* in spec */
+              arg = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escADD:
+            {
+              CF2_F16Dot16  summand1;
+              CF2_F16Dot16  summand2;
+
+
+              FT_TRACE4(( " add\n" ));
+
+              summand2 = cf2_stack_popFixed( opStack );
+              summand1 = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, summand1 + summand2 );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escSUB:
+            {
+              CF2_F16Dot16  minuend;
+              CF2_F16Dot16  subtrahend;
+
+
+              FT_TRACE4(( " sub\n" ));
+
+              subtrahend = cf2_stack_popFixed( opStack );
+              minuend    = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, minuend - subtrahend );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escDIV:
+            {
+              CF2_F16Dot16  dividend;
+              CF2_F16Dot16  divisor;
+
+
+              FT_TRACE4(( " div\n" ));
+
+              divisor  = cf2_stack_popFixed( opStack );
+              dividend = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escNEG:
+            {
+              CF2_F16Dot16  arg;
+
+
+              FT_TRACE4(( " neg\n" ));
+
+              arg = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, -arg );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escEQ:
+            {
+              CF2_F16Dot16  arg1;
+              CF2_F16Dot16  arg2;
+
+
+              FT_TRACE4(( " eq\n" ));
+
+              arg2 = cf2_stack_popFixed( opStack );
+              arg1 = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushInt( opStack, arg1 == arg2 );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escDROP:
             FT_TRACE4(( " drop\n" ));
 
-            CF2_FIXME;
-            break;
+            (void)cf2_stack_popFixed( opStack );
+            continue; /* do not clear the stack */
 
-          case cf2_escPUT: /* in spec */
-            FT_TRACE4(( " put\n" ));
+          case cf2_escPUT:
+            {
+              CF2_F16Dot16  val;
+              CF2_Int       idx;
 
-            CF2_FIXME;
-            break;
 
-          case cf2_escGET: /* in spec */
-            FT_TRACE4(( " get\n" ));
+              FT_TRACE4(( " put\n" ));
 
-            CF2_FIXME;
-            break;
+              idx = cf2_stack_popInt( opStack );
+              val = cf2_stack_popFixed( opStack );
 
-          case cf2_escIFELSE: /* in spec */
-            FT_TRACE4(( " ifelse\n" ));
+              if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                storage[idx] = val;
+            }
+            continue; /* do not clear the stack */
 
-            CF2_FIXME;
-            break;
+          case cf2_escGET:
+            {
+              CF2_Int  idx;
 
+
+              FT_TRACE4(( " get\n" ));
+
+              idx = cf2_stack_popInt( opStack );
+
+              if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                cf2_stack_pushFixed( opStack, storage[idx] );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escIFELSE:
+            {
+              CF2_F16Dot16  arg1;
+              CF2_F16Dot16  arg2;
+              CF2_F16Dot16  cond1;
+              CF2_F16Dot16  cond2;
+
+
+              FT_TRACE4(( " ifelse\n" ));
+
+              cond2 = cf2_stack_popFixed( opStack );
+              cond1 = cf2_stack_popFixed( opStack );
+              arg2  = cf2_stack_popFixed( opStack );
+              arg1  = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
+            }
+            continue; /* do not clear the stack */
+
           case cf2_escRANDOM: /* in spec */
             FT_TRACE4(( " random\n" ));
 
@@ -919,41 +1026,126 @@
             CF2_FIXME;
             break;
 
-          case cf2_escMUL: /* in spec */
-            FT_TRACE4(( " mul\n" ));
+          case cf2_escMUL:
+            {
+              CF2_F16Dot16  factor1;
+              CF2_F16Dot16  factor2;
 
-            CF2_FIXME;
-            break;
 
-          case cf2_escSQRT: /* in spec */
-            FT_TRACE4(( " sqrt\n" ));
+              FT_TRACE4(( " mul\n" ));
 
-            CF2_FIXME;
-            break;
+              factor2 = cf2_stack_popFixed( opStack );
+              factor1 = cf2_stack_popFixed( opStack );
 
-          case cf2_escDUP: /* in spec */
-            FT_TRACE4(( " dup\n" ));
+              cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
+            }
+            continue; /* do not clear the stack */
 
-            CF2_FIXME;
-            break;
+          case cf2_escSQRT:
+            {
+              CF2_F16Dot16  arg;
 
-          case cf2_escEXCH: /* in spec */
-            FT_TRACE4(( " exch\n" ));
 
-            CF2_FIXME;
-            break;
+              FT_TRACE4(( " sqrt\n" ));
 
-          case cf2_escINDEX: /* in spec */
-            FT_TRACE4(( " index\n" ));
+              arg = cf2_stack_popFixed( opStack );
+              if ( arg > 0 )
+              {
+                FT_Fixed  root = arg;
+                FT_Fixed  new_root;
 
-            CF2_FIXME;
-            break;
 
-          case cf2_escROLL: /* in spec */
-            FT_TRACE4(( " roll\n" ));
+                /* Babylonian method */
+                for (;;)
+                {
+                  new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
+                  if ( new_root == root )
+                    break;
+                  root = new_root;
+                }
+                arg = new_root;
+              }
+              else
+                arg = 0;
 
-            CF2_FIXME;
-            break;
+              cf2_stack_pushFixed( opStack, arg );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escDUP:
+            {
+              CF2_F16Dot16  arg;
+
+
+              FT_TRACE4(( " dup\n" ));
+
+              arg = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, arg );
+              cf2_stack_pushFixed( opStack, arg );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escEXCH:
+            {
+              CF2_F16Dot16  arg1;
+              CF2_F16Dot16  arg2;
+
+
+              FT_TRACE4(( " exch\n" ));
+
+              arg2 = cf2_stack_popFixed( opStack );
+              arg1 = cf2_stack_popFixed( opStack );
+
+              cf2_stack_pushFixed( opStack, arg2 );
+              cf2_stack_pushFixed( opStack, arg1 );
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escINDEX:
+            {
+              CF2_Int   idx;
+              CF2_UInt  size;
+
+
+              FT_TRACE4(( " index\n" ));
+
+              idx  = cf2_stack_popInt( opStack );
+              size = cf2_stack_count( opStack );
+
+              if ( size > 0 )
+              {
+                /* for `cf2_stack_getReal', index 0 is bottom of stack */
+                CF2_UInt  gr_idx;
+
+
+                if ( idx < 0 )
+                  gr_idx = size - 1;
+                else if ( (CF2_UInt)idx >= size )
+                  gr_idx = 0;
+                else
+                  gr_idx = size - 1 - (CF2_UInt)idx;
+
+                cf2_stack_pushFixed( opStack,
+                                     cf2_stack_getReal( opStack, gr_idx ) );
+              }
+            }
+            continue; /* do not clear the stack */
+
+          case cf2_escROLL:
+            {
+              CF2_Int  idx;
+              CF2_Int  count;
+
+
+              FT_TRACE4(( " roll\n" ));
+
+              idx   = cf2_stack_popInt( opStack );
+              count = cf2_stack_popInt( opStack );
+
+              cf2_stack_roll( opStack, count, idx );
+            }
+            continue; /* do not clear the stack */
 
           case cf2_escHFLEX:
             {
--- a/src/cff/cf2stack.c
+++ b/src/cff/cf2stack.c
@@ -145,7 +145,7 @@
 
 
   /* Note: type mismatch is silently cast */
-  /* TODO: check this */
+  /* TODO: check this                     */
   FT_LOCAL_DEF( CF2_Fixed )
   cf2_stack_popFixed( CF2_Stack  stack )
   {
@@ -170,7 +170,7 @@
 
 
   /* Note: type mismatch is silently cast */
-  /* TODO: check this */
+  /* TODO: check this                     */
   FT_LOCAL_DEF( CF2_Fixed )
   cf2_stack_getReal( CF2_Stack  stack,
                      CF2_UInt   idx )
@@ -191,6 +191,86 @@
       return cf2_fracToFixed( stack->buffer[idx].u.f );
     default:
       return stack->buffer[idx].u.r;
+    }
+  }
+
+
+  FT_LOCAL( void )
+  cf2_stack_roll( CF2_Stack  stack,
+                  CF2_Int    count,
+                  CF2_Int    shift )
+  {
+    /* we initialize this variable to avoid compiler warnings */
+    CF2_StackNumber  last = { { 0 }, CF2_NumberInt };
+
+    CF2_Int  start_idx, idx, i;
+
+
+    if ( count < 2 )
+      return; /* nothing to do (values 0 and 1), or undefined value */
+
+    if ( (CF2_UInt)count > cf2_stack_count( stack ) )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return;
+    }
+
+    if ( shift < 0 )
+      shift = -( ( -shift ) % count );
+    else
+      shift %= count;
+
+    if ( shift == 0 )
+      return; /* nothing to do */
+
+    /* We use the following algorithm to do the rolling, */
+    /* which needs two temporary variables only.         */
+    /*                                                   */
+    /* Example:                                          */
+    /*                                                   */
+    /*   count = 8                                       */
+    /*   shift = 2                                       */
+    /*                                                   */
+    /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
+    /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
+    /*                                                   */
+    /* The value of index 0 gets moved to index 2, while */
+    /* the old value of index 2 gets moved to index 4,   */
+    /* and so on.  We thus have the following copying    */
+    /* chains for shift value 2.                         */
+    /*                                                   */
+    /*   0 -> 2 -> 4 -> 6 -> 0                           */
+    /*   1 -> 3 -> 5 -> 7 -> 1                           */
+    /*                                                   */
+    /* If `count' and `shift' are incommensurable, we    */
+    /* have a single chain only.  Otherwise, increase    */
+    /* the start index by 1 after the first chain, then  */
+    /* do the next chain until all elements in all       */
+    /* chains are handled.                               */
+
+    start_idx = -1;
+    idx       = -1;
+    for ( i = 0; i < count; i++ )
+    {
+      CF2_StackNumber  tmp;
+
+
+      if ( start_idx == idx )
+      {
+        start_idx++;
+        idx  = start_idx;
+        last = stack->buffer[idx];
+      }
+
+      idx += shift;
+      if ( idx >= count )
+        idx -= count;
+      else if ( idx < 0 )
+        idx += count;
+
+      tmp                = stack->buffer[idx];
+      stack->buffer[idx] = last;
+      last               = tmp;
     }
   }
 
--- a/src/cff/cf2stack.h
+++ b/src/cff/cf2stack.h
@@ -94,6 +94,11 @@
                      CF2_UInt   idx );
 
   FT_LOCAL( void )
+  cf2_stack_roll( CF2_Stack  stack,
+                  CF2_Int    count,
+                  CF2_Int    idx );
+
+  FT_LOCAL( void )
   cf2_stack_clear( CF2_Stack  stack );