Home | History | Annotate | Download | only in psaux
      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 */
    329