• 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;        /* for FT_QNEW */
58     CF2_Stack  stack = NULL;
59 
60 
61     if ( FT_QNEW( stack ) )
62       return NULL;
63 
64     stack->memory = memory;
65     stack->error  = e;
66 
67     /* allocate the stack buffer */
68     if ( FT_QNEW_ARRAY( stack->buffer, stackSize ) )
69     {
70       FT_FREE( stack );
71       return NULL;
72     }
73 
74     stack->stackSize = stackSize;
75     stack->top       = stack->buffer;     /* empty stack */
76 
77     return stack;
78   }
79 
80 
81   FT_LOCAL_DEF( void )
cf2_stack_free(CF2_Stack stack)82   cf2_stack_free( CF2_Stack  stack )
83   {
84     if ( stack )
85     {
86       FT_Memory  memory = stack->memory;
87 
88       /* free the buffer */
89       FT_FREE( stack->buffer );
90 
91       /* free the main structure */
92       FT_FREE( stack );
93     }
94   }
95 
96 
97   FT_LOCAL_DEF( CF2_UInt )
cf2_stack_count(CF2_Stack stack)98   cf2_stack_count( CF2_Stack  stack )
99   {
100     return (CF2_UInt)( stack->top - stack->buffer );
101   }
102 
103 
104   FT_LOCAL_DEF( void )
cf2_stack_pushInt(CF2_Stack stack,CF2_Int val)105   cf2_stack_pushInt( CF2_Stack  stack,
106                      CF2_Int    val )
107   {
108     if ( stack->top == stack->buffer + stack->stackSize )
109     {
110       CF2_SET_ERROR( stack->error, Stack_Overflow );
111       return;     /* stack overflow */
112     }
113 
114     stack->top->u.i  = val;
115     stack->top->type = CF2_NumberInt;
116     stack->top++;
117   }
118 
119 
120   FT_LOCAL_DEF( void )
cf2_stack_pushFixed(CF2_Stack stack,CF2_Fixed val)121   cf2_stack_pushFixed( CF2_Stack  stack,
122                        CF2_Fixed  val )
123   {
124     if ( stack->top == stack->buffer + stack->stackSize )
125     {
126       CF2_SET_ERROR( stack->error, Stack_Overflow );
127       return;     /* stack overflow */
128     }
129 
130     stack->top->u.r  = val;
131     stack->top->type = CF2_NumberFixed;
132     stack->top++;
133   }
134 
135 
136   /* this function is only allowed to pop an integer type */
137   FT_LOCAL_DEF( CF2_Int )
cf2_stack_popInt(CF2_Stack stack)138   cf2_stack_popInt( CF2_Stack  stack )
139   {
140     if ( stack->top == stack->buffer )
141     {
142       CF2_SET_ERROR( stack->error, Stack_Underflow );
143       return 0;   /* underflow */
144     }
145     if ( stack->top[-1].type != CF2_NumberInt )
146     {
147       CF2_SET_ERROR( stack->error, Syntax_Error );
148       return 0;   /* type mismatch */
149     }
150 
151     stack->top--;
152 
153     return stack->top->u.i;
154   }
155 
156 
157   /* Note: type mismatch is silently cast */
158   /* TODO: check this                     */
159   FT_LOCAL_DEF( CF2_Fixed )
cf2_stack_popFixed(CF2_Stack stack)160   cf2_stack_popFixed( CF2_Stack  stack )
161   {
162     if ( stack->top == stack->buffer )
163     {
164       CF2_SET_ERROR( stack->error, Stack_Underflow );
165       return cf2_intToFixed( 0 );    /* underflow */
166     }
167 
168     stack->top--;
169 
170     switch ( stack->top->type )
171     {
172     case CF2_NumberInt:
173       return cf2_intToFixed( stack->top->u.i );
174     case CF2_NumberFrac:
175       return cf2_fracToFixed( stack->top->u.f );
176     default:
177       return stack->top->u.r;
178     }
179   }
180 
181 
182   /* Note: type mismatch is silently cast */
183   /* TODO: check this                     */
184   FT_LOCAL_DEF( CF2_Fixed )
cf2_stack_getReal(CF2_Stack stack,CF2_UInt idx)185   cf2_stack_getReal( CF2_Stack  stack,
186                      CF2_UInt   idx )
187   {
188     FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize );
189 
190     if ( idx >= cf2_stack_count( stack ) )
191     {
192       CF2_SET_ERROR( stack->error, Stack_Overflow );
193       return cf2_intToFixed( 0 );    /* bounds error */
194     }
195 
196     switch ( stack->buffer[idx].type )
197     {
198     case CF2_NumberInt:
199       return cf2_intToFixed( stack->buffer[idx].u.i );
200     case CF2_NumberFrac:
201       return cf2_fracToFixed( stack->buffer[idx].u.f );
202     default:
203       return stack->buffer[idx].u.r;
204     }
205   }
206 
207 
208   /* provide random access to stack */
209   FT_LOCAL_DEF( void )
cf2_stack_setReal(CF2_Stack stack,CF2_UInt idx,CF2_Fixed val)210   cf2_stack_setReal( CF2_Stack  stack,
211                      CF2_UInt   idx,
212                      CF2_Fixed  val )
213   {
214     if ( idx > cf2_stack_count( stack ) )
215     {
216       CF2_SET_ERROR( stack->error, Stack_Overflow );
217       return;
218     }
219 
220     stack->buffer[idx].u.r  = val;
221     stack->buffer[idx].type = CF2_NumberFixed;
222   }
223 
224 
225   /* discard (pop) num values from stack */
226   FT_LOCAL_DEF( void )
cf2_stack_pop(CF2_Stack stack,CF2_UInt num)227   cf2_stack_pop( CF2_Stack  stack,
228                  CF2_UInt   num )
229   {
230     if ( num > cf2_stack_count( stack ) )
231     {
232       CF2_SET_ERROR( stack->error, Stack_Underflow );
233       return;
234     }
235     stack->top -= num;
236   }
237 
238 
239   FT_LOCAL_DEF( void )
cf2_stack_roll(CF2_Stack stack,CF2_Int count,CF2_Int shift)240   cf2_stack_roll( CF2_Stack  stack,
241                   CF2_Int    count,
242                   CF2_Int    shift )
243   {
244     /* we initialize this variable to avoid compiler warnings */
245     CF2_StackNumber  last = { { 0 }, CF2_NumberInt };
246 
247     CF2_Int  start_idx, idx, i;
248 
249 
250     if ( count < 2 )
251       return; /* nothing to do (values 0 and 1), or undefined value */
252 
253     if ( (CF2_UInt)count > cf2_stack_count( stack ) )
254     {
255       CF2_SET_ERROR( stack->error, Stack_Overflow );
256       return;
257     }
258 
259     /* before C99 it is implementation-defined whether    */
260     /* the result of `%' is negative if the first operand */
261     /* is negative                                        */
262     if ( shift < 0 )
263       shift = -( ( -shift ) % count );
264     else
265       shift %= count;
266 
267     if ( shift == 0 )
268       return; /* nothing to do */
269 
270     /* We use the following algorithm to do the rolling, */
271     /* which needs two temporary variables only.         */
272     /*                                                   */
273     /* Example:                                          */
274     /*                                                   */
275     /*   count = 8                                       */
276     /*   shift = 2                                       */
277     /*                                                   */
278     /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
279     /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
280     /*                                                   */
281     /* The value of index 0 gets moved to index 2, while */
282     /* the old value of index 2 gets moved to index 4,   */
283     /* and so on.  We thus have the following copying    */
284     /* chains for shift value 2.                         */
285     /*                                                   */
286     /*   0 -> 2 -> 4 -> 6 -> 0                           */
287     /*   1 -> 3 -> 5 -> 7 -> 1                           */
288     /*                                                   */
289     /* If `count' and `shift' are incommensurable, we    */
290     /* have a single chain only.  Otherwise, increase    */
291     /* the start index by 1 after the first chain, then  */
292     /* do the next chain until all elements in all       */
293     /* chains are handled.                               */
294 
295     start_idx = -1;
296     idx       = -1;
297     for ( i = 0; i < count; i++ )
298     {
299       CF2_StackNumber  tmp;
300 
301 
302       if ( start_idx == idx )
303       {
304         start_idx++;
305         idx  = start_idx;
306         last = stack->buffer[idx];
307       }
308 
309       idx += shift;
310       if ( idx >= count )
311         idx -= count;
312       else if ( idx < 0 )
313         idx += count;
314 
315       tmp                = stack->buffer[idx];
316       stack->buffer[idx] = last;
317       last               = tmp;
318     }
319   }
320 
321 
322   FT_LOCAL_DEF( void )
cf2_stack_clear(CF2_Stack stack)323   cf2_stack_clear( CF2_Stack  stack )
324   {
325     stack->top = stack->buffer;
326   }
327 
328 
329 /* END */
330