• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <freetype/internal/ftdebug.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 )
cf2_stack_init(FT_Memory memory,FT_Error * e,FT_UInt stackSize)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       return NULL;
64 
65     /* initialize the structure; FT_NEW zeroes it */
66     stack->memory = memory;
67     stack->error  = e;
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 )
cf2_stack_free(CF2_Stack stack)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 )
cf2_stack_count(CF2_Stack stack)100   cf2_stack_count( CF2_Stack  stack )
101   {
102     return (CF2_UInt)( stack->top - stack->buffer );
103   }
104 
105 
106   FT_LOCAL_DEF( void )
cf2_stack_pushInt(CF2_Stack stack,CF2_Int val)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 )
cf2_stack_pushFixed(CF2_Stack stack,CF2_Fixed val)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 )
cf2_stack_popInt(CF2_Stack stack)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 )
cf2_stack_popFixed(CF2_Stack stack)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 )
cf2_stack_getReal(CF2_Stack stack,CF2_UInt idx)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 )
cf2_stack_setReal(CF2_Stack stack,CF2_UInt idx,CF2_Fixed val)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 )
cf2_stack_pop(CF2_Stack stack,CF2_UInt num)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 )
cf2_stack_roll(CF2_Stack stack,CF2_Int count,CF2_Int shift)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 )
cf2_stack_clear(CF2_Stack stack)325   cf2_stack_clear( CF2_Stack  stack )
326   {
327     stack->top = stack->buffer;
328   }
329 
330 
331 /* END */
332