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     /* before C99 it is implementation-defined whether    */
 262     /* the result of `%' is negative if the first operand */
 263     /* is negative                                        */
 264     if ( shift < 0 )
 265       shift = -( ( -shift ) % count );
 266     else
 267       shift %= count;
 268 
 269     if ( shift == 0 )
 270       return; /* nothing to do */
 271 
 272     /* We use the following algorithm to do the rolling, */
 273     /* which needs two temporary variables only.         */
 274     /*                                                   */
 275     /* Example:                                          */
 276     /*                                                   */
 277     /*   count = 8                                       */
 278     /*   shift = 2                                       */
 279     /*                                                   */
 280     /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
 281     /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
 282     /*                                                   */
 283     /* The value of index 0 gets moved to index 2, while */
 284     /* the old value of index 2 gets moved to index 4,   */
 285     /* and so on.  We thus have the following copying    */
 286     /* chains for shift value 2.                         */
 287     /*                                                   */
 288     /*   0 -> 2 -> 4 -> 6 -> 0                           */
 289     /*   1 -> 3 -> 5 -> 7 -> 1                           */
 290     /*                                                   */
 291     /* If `count' and `shift' are incommensurable, we    */
 292     /* have a single chain only.  Otherwise, increase    */
 293     /* the start index by 1 after the first chain, then  */
 294     /* do the next chain until all elements in all       */
 295     /* chains are handled.                               */
 296 
 297     start_idx = -1;
 298     idx       = -1;
 299     for ( i = 0; i < count; i++ )
 300     {
 301       CF2_StackNumber  tmp;
 302 
 303 
 304       if ( start_idx == idx )
 305       {
 306         start_idx++;
 307         idx  = start_idx;
 308         last = stack->buffer[idx];
 309       }
 310 
 311       idx += shift;
 312       if ( idx >= count )
 313         idx -= count;
 314       else if ( idx < 0 )
 315         idx += count;
 316 
 317       tmp                = stack->buffer[idx];
 318       stack->buffer[idx] = last;
 319       last               = tmp;
 320     }
 321   }
 322 
 323 
 324   FT_LOCAL_DEF( void )
 325   cf2_stack_clear( CF2_Stack  stack )
 326   {
 327     stack->top = stack->buffer;
 328   }
 329 
 330 
 331 /* END */