1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  psstack.c                                                              */
   4 /*                                                                         */
   5 /*    Adobe's code for emulating a CFF stack (body).                       */
   6 /*                                                                         */
   7 /*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
   8 /*                                                                         */
   9 /*  This software, and all works of authorship, whether in source or       */
  10 /*  object code form as indicated by the copyright notice(s) included      */
  11 /*  herein (collectively, the "Work") is made available, and may only be   */
  12 /*  used, modified, and distributed under the FreeType Project License,    */
  13 /*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
  14 /*  FreeType Project License, each contributor to the Work hereby grants   */
  15 /*  to any individual or legal entity exercising permissions granted by    */
  16 /*  the FreeType Project License and this section (hereafter, "You" or     */
  17 /*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
  18 /*  royalty-free, irrevocable (except as stated in this section) patent    */
  19 /*  license to make, have made, use, offer to sell, sell, import, and      */
  20 /*  otherwise transfer the Work, where such license applies only to those  */
  21 /*  patent claims licensable by such contributor that are necessarily      */
  22 /*  infringed by their contribution(s) alone or by combination of their    */
  23 /*  contribution(s) with the Work to which such contribution(s) was        */
  24 /*  submitted.  If You institute patent litigation against any entity      */
  25 /*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
  26 /*  the Work or a contribution incorporated within the Work constitutes    */
  27 /*  direct or contributory patent infringement, then any patent licenses   */
  28 /*  granted to You under this License for that Work shall terminate as of  */
  29 /*  the date such litigation is filed.                                     */
  30 /*                                                                         */
  31 /*  By using, modifying, or distributing the Work you indicate that you    */
  32 /*  have read and understood the terms and conditions of the               */
  33 /*  FreeType Project License as well as those provided in this section,    */
  34 /*  and you accept them fully.                                             */
  35 /*                                                                         */
  36 /***************************************************************************/
  37 
  38 
  39 #include "psft.h"
  40 #include FT_INTERNAL_DEBUG_H
  41 
  42 #include "psglue.h"
  43 #include "psfont.h"
  44 #include "psstack.h"
  45 
  46 #include "pserror.h"
  47 
  48 
  49   /* Allocate and initialize an instance of CF2_Stack.       */
  50   /* Note: This function returns NULL on error (does not set */
  51   /* `error').                                               */
  52   FT_LOCAL_DEF( CF2_Stack )
  53   cf2_stack_init( FT_Memory  memory,
  54                   FT_Error*  e,
  55                   FT_UInt    stackSize )
  56   {
  57     FT_Error  error = FT_Err_Ok;     /* for FT_NEW */
  58 
  59     CF2_Stack  stack = NULL;
  60 
  61 
  62     if ( !FT_NEW( stack ) )
  63     {
  64       /* initialize the structure; FT_NEW zeroes it */
  65       stack->memory = memory;
  66       stack->error  = e;
  67     }
  68 
  69     /* allocate the stack buffer */
  70     if ( FT_NEW_ARRAY( stack->buffer, stackSize ) )
  71     {
  72       FT_FREE( stack );
  73       return NULL;
  74     }
  75 
  76     stack->stackSize = stackSize;
  77     stack->top       = stack->buffer;     /* empty stack */
  78 
  79     return stack;
  80   }
  81 
  82 
  83   FT_LOCAL_DEF( void )
  84   cf2_stack_free( CF2_Stack  stack )
  85   {
  86     if ( stack )
  87     {
  88       FT_Memory  memory = stack->memory;
  89 
  90       /* free the buffer */
  91       FT_FREE( stack->buffer );
  92 
  93       /* free the main structure */
  94       FT_FREE( stack );
  95     }
  96   }
  97 
  98 
  99   FT_LOCAL_DEF( CF2_UInt )
 100   cf2_stack_count( CF2_Stack  stack )
 101   {
 102     return (CF2_UInt)( stack->top - stack->buffer );
 103   }
 104 
 105 
 106   FT_LOCAL_DEF( void )
 107   cf2_stack_pushInt( CF2_Stack  stack,
 108                      CF2_Int    val )
 109   {
 110     if ( stack->top == stack->buffer + stack->stackSize )
 111     {
 112       CF2_SET_ERROR( stack->error, Stack_Overflow );
 113       return;     /* stack overflow */
 114     }
 115 
 116     stack->top->u.i  = val;
 117     stack->top->type = CF2_NumberInt;
 118     stack->top++;
 119   }
 120 
 121 
 122   FT_LOCAL_DEF( void )
 123   cf2_stack_pushFixed( CF2_Stack  stack,
 124                        CF2_Fixed  val )
 125   {
 126     if ( stack->top == stack->buffer + stack->stackSize )
 127     {
 128       CF2_SET_ERROR( stack->error, Stack_Overflow );
 129       return;     /* stack overflow */
 130     }
 131 
 132     stack->top->u.r  = val;
 133     stack->top->type = CF2_NumberFixed;
 134     stack->top++;
 135   }
 136 
 137 
 138   /* this function is only allowed to pop an integer type */
 139   FT_LOCAL_DEF( CF2_Int )
 140   cf2_stack_popInt( CF2_Stack  stack )
 141   {
 142     if ( stack->top == stack->buffer )
 143     {
 144       CF2_SET_ERROR( stack->error, Stack_Underflow );
 145       return 0;   /* underflow */
 146     }
 147     if ( stack->top[-1].type != CF2_NumberInt )
 148     {
 149       CF2_SET_ERROR( stack->error, Syntax_Error );
 150       return 0;   /* type mismatch */
 151     }
 152 
 153     stack->top--;
 154 
 155     return stack->top->u.i;
 156   }
 157 
 158 
 159   /* Note: type mismatch is silently cast */
 160   /* TODO: check this                     */
 161   FT_LOCAL_DEF( CF2_Fixed )
 162   cf2_stack_popFixed( CF2_Stack  stack )
 163   {
 164     if ( stack->top == stack->buffer )
 165     {
 166       CF2_SET_ERROR( stack->error, Stack_Underflow );
 167       return cf2_intToFixed( 0 );    /* underflow */
 168     }
 169 
 170     stack->top--;
 171 
 172     switch ( stack->top->type )
 173     {
 174     case CF2_NumberInt:
 175       return cf2_intToFixed( stack->top->u.i );
 176     case CF2_NumberFrac:
 177       return cf2_fracToFixed( stack->top->u.f );
 178     default:
 179       return stack->top->u.r;
 180     }
 181   }
 182 
 183 
 184   /* Note: type mismatch is silently cast */
 185   /* TODO: check this                     */
 186   FT_LOCAL_DEF( CF2_Fixed )
 187   cf2_stack_getReal( CF2_Stack  stack,
 188                      CF2_UInt   idx )
 189   {
 190     FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize );
 191 
 192     if ( idx >= cf2_stack_count( stack ) )
 193     {
 194       CF2_SET_ERROR( stack->error, Stack_Overflow );
 195       return cf2_intToFixed( 0 );    /* bounds error */
 196     }
 197 
 198     switch ( stack->buffer[idx].type )
 199     {
 200     case CF2_NumberInt:
 201       return cf2_intToFixed( stack->buffer[idx].u.i );
 202     case CF2_NumberFrac:
 203       return cf2_fracToFixed( stack->buffer[idx].u.f );
 204     default:
 205       return stack->buffer[idx].u.r;
 206     }
 207   }
 208 
 209 
 210   /* provide random access to stack */
 211   FT_LOCAL_DEF( void )
 212   cf2_stack_setReal( CF2_Stack  stack,
 213                      CF2_UInt   idx,
 214                      CF2_Fixed  val )
 215   {
 216     if ( idx > cf2_stack_count( stack ) )
 217     {
 218       CF2_SET_ERROR( stack->error, Stack_Overflow );
 219       return;
 220     }
 221 
 222     stack->buffer[idx].u.r  = val;
 223     stack->buffer[idx].type = CF2_NumberFixed;
 224   }
 225 
 226 
 227   /* discard (pop) num values from stack */
 228   FT_LOCAL_DEF( void )
 229   cf2_stack_pop( CF2_Stack  stack,
 230                  CF2_UInt   num )
 231   {
 232     if ( num > cf2_stack_count( stack ) )
 233     {
 234       CF2_SET_ERROR( stack->error, Stack_Underflow );
 235       return;
 236     }
 237     stack->top -= num;
 238   }
 239 
 240 
 241   FT_LOCAL_DEF( void )
 242   cf2_stack_roll( CF2_Stack  stack,
 243                   CF2_Int    count,
 244                   CF2_Int    shift )
 245   {
 246     /* we initialize this variable to avoid compiler warnings */
 247     CF2_StackNumber  last = { { 0 }, CF2_NumberInt };
 248 
 249     CF2_Int  start_idx, idx, i;
 250 
 251 
 252     if ( count < 2 )
 253       return; /* nothing to do (values 0 and 1), or undefined value */
 254 
 255     if ( (CF2_UInt)count > cf2_stack_count( stack ) )
 256     {
 257       CF2_SET_ERROR( stack->error, Stack_Overflow );
 258       return;
 259     }
 260 
 261     if ( shift < 0 )
 262       shift = -( ( -shift ) % count );
 263     else
 264       shift %= count;
 265 
 266     if ( shift == 0 )
 267       return; /* nothing to do */
 268 
 269     /* We use the following algorithm to do the rolling, */
 270     /* which needs two temporary variables only.         */
 271     /*                                                   */
 272     /* Example:                                          */
 273     /*                                                   */
 274     /*   count = 8                                       */
 275     /*   shift = 2                                       */
 276     /*                                                   */
 277     /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
 278     /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
 279     /*                                                   */
 280     /* The value of index 0 gets moved to index 2, while */
 281     /* the old value of index 2 gets moved to index 4,   */
 282     /* and so on.  We thus have the following copying    */
 283     /* chains for shift value 2.                         */
 284     /*                                                   */
 285     /*   0 -> 2 -> 4 -> 6 -> 0                           */
 286     /*   1 -> 3 -> 5 -> 7 -> 1                           */
 287     /*                                                   */
 288     /* If `count' and `shift' are incommensurable, we    */
 289     /* have a single chain only.  Otherwise, increase    */
 290     /* the start index by 1 after the first chain, then  */
 291     /* do the next chain until all elements in all       */
 292     /* chains are handled.                               */
 293 
 294     start_idx = -1;
 295     idx       = -1;
 296     for ( i = 0; i < count; i++ )
 297     {
 298       CF2_StackNumber  tmp;
 299 
 300 
 301       if ( start_idx == idx )
 302       {
 303         start_idx++;
 304         idx  = start_idx;
 305         last = stack->buffer[idx];
 306       }
 307 
 308       idx += shift;
 309       if ( idx >= count )
 310         idx -= count;
 311       else if ( idx < 0 )
 312         idx += count;
 313 
 314       tmp                = stack->buffer[idx];
 315       stack->buffer[idx] = last;
 316       last               = tmp;
 317     }
 318   }
 319 
 320 
 321   FT_LOCAL_DEF( void )
 322   cf2_stack_clear( CF2_Stack  stack )
 323   {
 324     stack->top = stack->buffer;
 325   }
 326 
 327 
 328 /* END */