xref: /plan9/sys/src/cmd/gs/src/ttobjs.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2003 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: ttobjs.c,v 1.9 2004/12/21 20:13:41 igor Exp $ */
18 
19 /* Changes after FreeType: cut out the TrueType instruction interpreter. */
20 
21 /*******************************************************************
22  *
23  *  ttobjs.c                                                     1.0
24  *
25  *    Objects manager.
26  *
27  *  Copyright 1996-1998 by
28  *  David Turner, Robert Wilhelm, and Werner Lemberg.
29  *
30  *  This file is part of the FreeType project, and may only be used
31  *  modified and distributed under the terms of the FreeType project
32  *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
33  *  this file you indicate that you have read the license and
34  *  understand and accept it fully.
35  *
36  ******************************************************************/
37 
38 #include "ttmisc.h"
39 
40 #include "ttfoutl.h"
41 #include "ttobjs.h"
42 #include "ttcalc.h"
43 #include "ttload.h"
44 #include "ttinterp.h"
45 
46 /* Add extensions definition */
47 #ifdef TT_EXTEND_ENGINE
48 #endif
49 
50 
51 
52 /*******************************************************************
53  *                                                                 *
54  *                     CODERANGE FUNCTIONS                         *
55  *                                                                 *
56  *                                                                 *
57  *******************************************************************/
58 
59 /*******************************************************************
60  *
61  *  Function    :  Goto_CodeRange
62  *
63  *  Description :  Switch to a new code range (updates Code and IP).
64  *
65  *  Input  :  exec    target execution context
66  *            range   new execution code range
67  *            IP      new IP in new code range
68  *
69  *  Output :  SUCCESS on success.  FAILURE on error (no code range).
70  *
71  *****************************************************************/
72 
Goto_CodeRange(PExecution_Context exec,Int range,Int IP)73   TT_Error  Goto_CodeRange( PExecution_Context  exec, Int  range, Int  IP )
74   {
75     PCodeRange  cr;
76 
77 
78     if ( range < 1 || range > 3 )
79       return TT_Err_Bad_Argument;
80 
81     cr = &exec->codeRangeTable[range - 1];
82 
83     if ( cr->Base == NULL )
84       return TT_Err_Invalid_CodeRange;
85 
86     /* NOTE:  Because the last instruction of a program may be a CALL */
87     /*        which will return to the first byte *after* the code    */
88     /*        range, we test for IP <= Size, instead of IP < Size.    */
89 
90     if ( IP > cr->Size )
91       return TT_Err_Code_Overflow;
92 
93     exec->code     = cr->Base;
94     exec->codeSize = cr->Size;
95     exec->IP       = IP;
96     exec->curRange = range;
97 
98     return TT_Err_Ok;
99   }
100 
101 /*******************************************************************
102  *
103  *  Function    :  Unset_CodeRange
104  *
105  *  Description :  Unsets the code range pointer.
106  *
107  *  Input  :  exec    target execution context
108  *
109  *  Output :
110  *
111  *  Note   : The pointer must be unset after used to avoid pending pointers
112  *           while a garbager invokation.
113  *
114  *****************************************************************/
115 
Unset_CodeRange(PExecution_Context exec)116   void  Unset_CodeRange( PExecution_Context  exec )
117   {
118     exec->code = 0;
119     exec->codeSize = 0;
120   }
121 
122 /*******************************************************************
123  *
124  *  Function    :  Get_CodeRange
125  *
126  *  Description :  Returns a pointer to a given code range.  Should
127  *                 be used only by the debugger.  Returns NULL if
128  *                 'range' is out of current bounds.
129  *
130  *  Input  :  exec    target execution context
131  *            range   new execution code range
132  *
133  *  Output :  Pointer to the code range record.  NULL on failure.
134  *
135  *****************************************************************/
136 
Get_CodeRange(PExecution_Context exec,Int range)137   PCodeRange  Get_CodeRange( PExecution_Context  exec, Int  range )
138   {
139     if ( range < 1 || range > 3 )
140       return (PCodeRange)NULL;
141     else                /* arrays start with 1 in Pascal, and with 0 in C */
142       return &exec->codeRangeTable[range - 1];
143   }
144 
145 
146 /*******************************************************************
147  *
148  *  Function    :  Set_CodeRange
149  *
150  *  Description :  Sets a code range.
151  *
152  *  Input  :  exec    target execution context
153  *            range   code range index
154  *            base    new code base
155  *            length  sange size in bytes
156  *
157  *  Output :  SUCCESS on success.  FAILURE on error.
158  *
159  *****************************************************************/
160 
Set_CodeRange(PExecution_Context exec,Int range,void * base,Int length)161   TT_Error  Set_CodeRange( PExecution_Context  exec,
162                            Int                 range,
163                            void*               base,
164                            Int                 length )
165   {
166     if ( range < 1 || range > 3 )
167       return TT_Err_Bad_Argument;
168 
169     exec->codeRangeTable[range - 1].Base = (unsigned char*)base;
170     exec->codeRangeTable[range - 1].Size = length;
171 
172     return TT_Err_Ok;
173   }
174 
175 
176 /*******************************************************************
177  *
178  *  Function    :  Clear_CodeRange
179  *
180  *  Description :  Clears a code range.
181  *
182  *  Input  :  exec    target execution context
183  *            range   code range index
184  *
185  *  Output :  SUCCESS on success.  FAILURE on error.
186  *
187  *  Note   : Does not set the Error variable.
188  *
189  *****************************************************************/
190 
Clear_CodeRange(PExecution_Context exec,Int range)191   TT_Error Clear_CodeRange( PExecution_Context  exec, Int  range )
192   {
193     if ( range < 1 || range > 3 )
194       return TT_Err_Bad_Argument;
195 
196     exec->codeRangeTable[range - 1].Base = (Byte*)NULL;
197     exec->codeRangeTable[range - 1].Size = 0;
198 
199     return TT_Err_Ok;
200   }
201 
202 
203 
204 /*******************************************************************
205  *                                                                 *
206  *                EXECUTION CONTEXT ROUTINES                       *
207  *                                                                 *
208  *                                                                 *
209  *******************************************************************/
210 
211 
212 #define FREE(ptr) { mem->free(mem, ptr, "ttobjs.c"); ptr = NULL; }
213 #define ALLOC_ARRAY(ptr, old_count, count, type) \
214 	(old_count >= count ? 0 : \
215 	  !(free_aux(mem, ptr),   \
216 	    ptr = mem->alloc_bytes(mem, (count) * sizeof(type), "ttobjs.c")))
217 #define SETMAX(a, b) a = (a > b ? a : b)
218 
free_aux(ttfMemory * mem,void * ptr)219 static int free_aux(ttfMemory *mem, void *ptr)
220 {
221     mem->free(mem, ptr, "ttobjs.c");
222     return 0;
223 }
224 
225 /*******************************************************************
226  *
227  *  Function    :  Context_Destroy
228  *
229  *****************************************************************/
230 
Context_Destroy(void * _context)231  TT_Error  Context_Destroy( void*  _context )
232  {
233    PExecution_Context  exec = (PExecution_Context)_context;
234    ttfMemory *mem;
235 
236    if ( !exec )
237      return TT_Err_Ok;
238    if ( !exec->current_face ) {
239      /* This may happen while closing a high level device, when allocator runs out of memory.
240         A test case is 01_001.pdf with pdfwrite and a small vmthreshold.
241      */
242      return TT_Err_Out_Of_Memory;
243    }
244    if (--exec->lock)
245      return TT_Err_Ok; /* Still in use */
246 
247    mem = exec->current_face->font->tti->ttf_memory;
248 
249    /* points zone */
250    FREE( exec->pts.cur_y );
251    FREE( exec->pts.cur_x );
252    FREE( exec->pts.org_y );
253    FREE( exec->pts.org_x );
254    FREE( exec->pts.touch );
255    FREE( exec->pts.contours );
256    exec->pts.n_points   = 0;
257    exec->pts.n_contours = 0;
258 
259    /* twilight zone */
260    FREE( exec->twilight.touch );
261    FREE( exec->twilight.cur_y );
262    FREE( exec->twilight.cur_x );
263    FREE( exec->twilight.org_y );
264    FREE( exec->twilight.org_x );
265    FREE( exec->twilight.contours );
266    exec->twilight.n_points   = 0;
267    exec->twilight.n_contours = 0;
268 
269    /* free stack */
270    FREE( exec->stack );
271    exec->stackSize = 0;
272 
273    /* free call stack */
274    FREE( exec->callStack );
275    exec->callSize = 0;
276    exec->callTop  = 0;
277 
278    /* free glyph code range */
279    exec->glyphSize = 0;
280    exec->maxGlyphSize = 0;
281 
282    exec->current_face    = (PFace)NULL;
283 
284    return TT_Err_Ok;
285  }
286 
287 /*******************************************************************
288  *
289  *  Function    :  Context_Create
290  *
291  *****************************************************************/
292 
Context_Create(void * _context,void * _face)293  TT_Error  Context_Create( void*  _context, void*  _face )
294  {
295    /* Note : The function name is a kind of misleading due to our improvement.
296     * Now it adjusts (enhances) the context for the specified face.
297     * We keep the old Free Type's name for easier localization of our changes.
298     * The context must be initialized with zeros before the first call.
299     * (igorm).
300     */
301    PExecution_Context  exec = (PExecution_Context)_context;
302 
303    PFace        face = (PFace)_face;
304    ttfMemory   *mem = face->font->tti->ttf_memory;
305    TMaxProfile *maxp = &face->maxProfile;
306    Int          n_points, n_twilight;
307    Int          callSize, stackSize;
308 
309    callSize  = 32;
310 
311    /* reserve a little extra for broken fonts like courbs or timesbs */
312    stackSize = maxp->maxStackElements + 32;
313 
314    n_points        = face->maxPoints + 2;
315    n_twilight      = maxp->maxTwilightPoints;
316 
317    if ( ALLOC_ARRAY( exec->callStack, exec->callSize, callSize, TCallRecord ) ||
318         /* reserve interpreter call stack */
319 
320         ALLOC_ARRAY( exec->stack, exec->stackSize, stackSize, Long )           ||
321         /* reserve interpreter stack */
322 
323         ALLOC_ARRAY( exec->pts.org_x, exec->n_points, n_points, TT_F26Dot6 )        ||
324         ALLOC_ARRAY( exec->pts.org_y, exec->n_points, n_points, TT_F26Dot6 )        ||
325         ALLOC_ARRAY( exec->pts.cur_x, exec->n_points, n_points, TT_F26Dot6 )        ||
326         ALLOC_ARRAY( exec->pts.cur_y, exec->n_points, n_points, TT_F26Dot6 )        ||
327         ALLOC_ARRAY( exec->pts.touch, exec->n_points, n_points, Byte )                          ||
328         /* reserve points zone */
329 
330         ALLOC_ARRAY( exec->twilight.org_x, exec->twilight.n_points, n_twilight, TT_F26Dot6 ) ||
331         ALLOC_ARRAY( exec->twilight.org_y, exec->twilight.n_points, n_twilight, TT_F26Dot6 ) ||
332         ALLOC_ARRAY( exec->twilight.cur_x, exec->twilight.n_points, n_twilight, TT_F26Dot6 ) ||
333         ALLOC_ARRAY( exec->twilight.cur_y, exec->twilight.n_points, n_twilight, TT_F26Dot6 ) ||
334         ALLOC_ARRAY( exec->twilight.touch, exec->twilight.n_points, n_twilight, Byte )                   ||
335         /* reserve twilight zone */
336 
337         ALLOC_ARRAY( exec->pts.contours, exec->n_contours, face->maxContours, UShort )
338         /* reserve contours array */
339       )
340      goto Fail_Memory;
341 
342      SETMAX(exec->callSize, callSize);
343      SETMAX(exec->stackSize, stackSize);
344      SETMAX(exec->twilight.n_points, n_twilight);
345      SETMAX(exec->maxGlyphSize, maxp->maxSizeOfInstructions);
346      SETMAX(exec->n_contours, face->maxContours);
347      SETMAX(exec->n_points, n_points);
348      exec->lock++;
349 
350      return TT_Err_Ok;
351 
352   Fail_Memory:
353     /* Context_Destroy( exec ); Don't release buffers because the context is shared. */
354     return TT_Err_Out_Of_Memory;
355  }
356 
357 
358 /*******************************************************************
359  *
360  *  Function    :  Context_Load
361  *
362  *****************************************************************/
363 
Context_Load(PExecution_Context exec,PInstance ins)364  TT_Error Context_Load( PExecution_Context  exec,
365                         PInstance           ins )
366  {
367    Int  i;
368 
369 
370    exec->current_face = ins->face;
371 
372    exec->numFDefs = ins->numFDefs;
373    exec->numIDefs = ins->numIDefs;
374    exec->FDefs    = ins->FDefs;
375    exec->IDefs    = ins->IDefs;
376    exec->countIDefs = ins->countIDefs;
377    memcpy(exec->IDefPtr, ins->IDefPtr, sizeof(exec->IDefPtr));
378 
379    exec->metrics  = ins->metrics;
380 
381    for ( i = 0; i < MAX_CODE_RANGES; i++ )
382      exec->codeRangeTable[i] = ins->codeRangeTable[i];
383 
384    exec->pts.n_points   = 0;
385    exec->pts.n_contours = 0;
386 
387    exec->instruction_trap = FALSE;
388 
389    /* set default graphics state */
390    exec->GS = ins->GS;
391 
392    exec->cvtSize = ins->cvtSize;
393    exec->cvt     = ins->cvt;
394 
395    exec->storeSize = ins->storeSize;
396    exec->storage   = ins->storage;
397 
398    return TT_Err_Ok;
399  }
400 
401 
402 /*******************************************************************
403  *
404  *  Function    :  Context_Save
405  *
406  *****************************************************************/
407 
Context_Save(PExecution_Context exec,PInstance ins)408  TT_Error  Context_Save( PExecution_Context  exec,
409                          PInstance           ins )
410  {
411    Int  i;
412 
413    for ( i = 0; i < MAX_CODE_RANGES; i++ ) {
414      ins->codeRangeTable[i] = exec->codeRangeTable[i];
415      exec->codeRangeTable[i].Base = 0;
416      exec->codeRangeTable[i].Size = 0;
417    }
418    exec->numFDefs = 0;
419    exec->numIDefs = 0;
420    memcpy(ins->IDefPtr, exec->IDefPtr, sizeof(ins->IDefPtr));
421    ins->countIDefs = exec->countIDefs;
422    exec->countIDefs = 0;
423    exec->FDefs    = 0;
424    exec->IDefs    = 0;
425    exec->cvtSize = 0;
426    exec->cvt     = 0;
427    exec->storeSize = 0;
428    exec->storage   = 0;
429    exec->current_face = 0;
430 
431    return TT_Err_Ok;
432  }
433 
434 
435 /*******************************************************************
436  *
437  *  Function    :  Context_Run
438  *
439  *****************************************************************/
440 
Context_Run(PExecution_Context exec,Bool debug)441  TT_Error  Context_Run( PExecution_Context  exec,
442                         Bool                debug )
443  {
444    TT_Error  error;
445 
446 
447    if ( ( error = Goto_CodeRange( exec, TT_CodeRange_Glyph, 0 ) ) )
448      return error;
449 
450    exec->zp0 = exec->pts;
451    exec->zp1 = exec->pts;
452    exec->zp2 = exec->pts;
453 
454    exec->GS.gep0 = 1;
455    exec->GS.gep1 = 1;
456    exec->GS.gep2 = 1;
457 
458    exec->GS.projVector.x = 0x4000;
459    exec->GS.projVector.y = 0x0000;
460 
461    exec->GS.freeVector = exec->GS.projVector;
462    exec->GS.dualVector = exec->GS.projVector;
463 
464    exec->GS.round_state = 1;
465    exec->GS.loop        = 1;
466 
467    /* some glyphs leave something on the stack. so we clean it */
468    /* before a new execution.                                  */
469    exec->top     = 0;
470    exec->callTop = 0;
471 
472    if ( !debug ) {
473      error = RunIns( exec );
474      Unset_CodeRange(exec);
475      return error;
476    } else
477      return TT_Err_Ok;
478  }
479 
480 
481   const TGraphicsState  Default_GraphicsState =
482   {
483     0, 0, 0,
484     { 0x4000, 0 },
485     { 0x4000, 0 },
486     { 0x4000, 0 },
487     1, 64, 1,
488     TRUE, 68, 0, 0, 9, 3,
489     0, FALSE, 2, 1, 1, 1
490   };
491 
492 
493 
494 /*******************************************************************
495  *                                                                 *
496  *                     INSTANCE  FUNCTIONS                         *
497  *                                                                 *
498  *                                                                 *
499  *******************************************************************/
500 
501 /*******************************************************************
502  *
503  *  Function    : Instance_Destroy
504  *
505  *  Description :
506  *
507  *  Input  :  _instance   the instance object to destroy
508  *
509  *  Output :  error code.
510  *
511  ******************************************************************/
512 
Instance_Destroy(void * _instance)513   TT_Error  Instance_Destroy( void* _instance )
514   {
515     PInstance  ins = (PInstance)_instance;
516     ttfMemory *mem;
517 
518     if ( !_instance )
519       return TT_Err_Ok;
520     if ( !ins->face ) {
521       /* This may happen while closing a high level device, when allocator runs out of memory.
522          A test case is 01_001.pdf with pdfwrite and a small vmthreshold.
523       */
524       return TT_Err_Out_Of_Memory;
525     }
526     mem = ins->face->font->tti->ttf_memory;
527 
528     FREE( ins->cvt );
529     ins->cvtSize = 0;
530 
531     FREE( ins->FDefs );
532     FREE( ins->IDefs );
533     FREE( ins->storage );
534     ins->numFDefs = 0;
535     ins->numIDefs = 0;
536 
537     ins->face = (PFace)NULL;
538     ins->valid = FALSE;
539 
540     return TT_Err_Ok;
541   }
542 
543 
544 /*******************************************************************
545  *
546  *  Function    : Instance_Create
547  *
548  *  Description :
549  *
550  *  Input  :  _instance    instance record to initialize
551  *            _face        parent face object
552  *
553  *  Output :  Error code.  All partially built subtables are
554  *            released on error.
555  *
556  ******************************************************************/
557 
Instance_Create(void * _instance,void * _face)558   TT_Error  Instance_Create( void*  _instance,
559                              void*  _face )
560   {
561     PInstance ins  = (PInstance)_instance;
562     PFace     face = (PFace)_face;
563     ttfMemory *mem = face->font->tti->ttf_memory;
564     PMaxProfile  maxp = &face->maxProfile;
565     Int       i;
566 
567     ins->FDefs=NULL;
568     ins->IDefs=NULL;
569     ins->cvt=NULL;
570     ins->storage=NULL;
571 
572     ins->face = face;
573     ins->valid = FALSE;
574 
575     ins->numFDefs = maxp->maxFunctionDefs;
576     ins->numIDefs = maxp->maxInstructionDefs;
577     ins->countIDefs = 0;
578     if (maxp->maxInstructionDefs > 255)
579 	goto Fail_Memory;
580     memset(ins->IDefPtr, (Byte)ins->numIDefs, sizeof(ins->IDefPtr));
581     if (ins->numFDefs < 50)
582 	ins->numFDefs = 50; /* Bug 687858 */
583     ins->cvtSize  = face->cvtSize;
584 
585     ins->metrics.pointSize    = 10 * 64;     /* default pointsize  = 10pts */
586 
587     ins->metrics.x_resolution = 96;          /* default resolution = 96dpi */
588     ins->metrics.y_resolution = 96;
589 
590     ins->metrics.x_ppem = 0;
591     ins->metrics.y_ppem = 0;
592 
593     ins->metrics.rotated   = FALSE;
594     ins->metrics.stretched = FALSE;
595 
596     ins->storeSize = maxp->maxStorage;
597 
598     for ( i = 0; i < 4; i++ )
599       ins->metrics.compensations[i] = 0;     /* Default compensations */
600 
601     if ( ALLOC_ARRAY( ins->FDefs, 0, ins->numFDefs, TDefRecord )  ||
602          ALLOC_ARRAY( ins->IDefs, 0, ins->numIDefs, TDefRecord )  ||
603          ALLOC_ARRAY( ins->cvt, 0, ins->cvtSize, Long )           ||
604          ALLOC_ARRAY( ins->storage, 0, ins->storeSize, Long )     )
605       goto Fail_Memory;
606 
607     memset (ins->FDefs, 0, ins->numFDefs * sizeof(TDefRecord));
608     memset (ins->IDefs, 0, ins->numIDefs * sizeof(TDefRecord));
609 
610     ins->GS = Default_GraphicsState;
611 
612     return TT_Err_Ok;
613 
614   Fail_Memory:
615     Instance_Destroy( ins );
616     return TT_Err_Out_Of_Memory;
617   }
618 
619 /*******************************************************************
620  *
621  *  Function    : Instance_Init
622  *
623  *  Description : Initialize a fresh new instance.
624  *                Executes the font program if any is found.
625  *
626  *  Input  :  _instance   the instance object to destroy
627  *
628  *  Output :  Error code.
629  *
630  ******************************************************************/
631 
Instance_Init(PInstance ins)632   TT_Error  Instance_Init( PInstance  ins )
633   {
634     PExecution_Context  exec;
635 
636     TT_Error  error;
637     PFace     face = ins->face;
638 
639     exec = ins->face->font->exec;
640     /* debugging instances have their own context */
641 
642     ins->GS = Default_GraphicsState;
643 
644     Context_Load( exec, ins );
645 
646     exec->callTop   = 0;
647     exec->top       = 0;
648 
649     exec->period    = 64;
650     exec->phase     = 0;
651     exec->threshold = 0;
652 
653     exec->metrics.x_ppem    = 0;
654     exec->metrics.y_ppem    = 0;
655     exec->metrics.pointSize = 0;
656     exec->metrics.x_scale1  = 0;
657     exec->metrics.x_scale2  = 1;
658     exec->metrics.y_scale1  = 0;
659     exec->metrics.y_scale2  = 1;
660 
661     exec->metrics.ppem      = 0;
662     exec->metrics.scale1    = 0;
663     exec->metrics.scale2    = 1;
664     exec->metrics.ratio     = 1 << 16;
665 
666     exec->instruction_trap = FALSE;
667 
668     exec->cvtSize = ins->cvtSize;
669     exec->cvt     = ins->cvt;
670 
671     exec->F_dot_P = 0x10000;
672 
673     /* allow font program execution */
674     Set_CodeRange( exec,
675                    TT_CodeRange_Font,
676                    face->fontProgram,
677                    face->fontPgmSize );
678 
679     /* disable CVT and glyph programs coderange */
680     Clear_CodeRange( exec, TT_CodeRange_Cvt );
681     Clear_CodeRange( exec, TT_CodeRange_Glyph );
682 
683     if ( face->fontPgmSize > 0 )
684     {
685       error = Goto_CodeRange( exec, TT_CodeRange_Font, 0 );
686       if ( error )
687         goto Fin;
688 
689       error = RunIns( exec );
690       Unset_CodeRange(exec);
691     }
692     else
693       error = TT_Err_Ok;
694 
695   Fin:
696     Context_Save( exec, ins );
697 
698     ins->valid = FALSE;
699 
700     return error;
701   }
702 
703 
704 /*******************************************************************
705  *
706  *  Function    : Instance_Reset
707  *
708  *  Description : Resets an instance to a new pointsize/transform.
709  *                Executes the cvt program if any is found.
710  *
711  *  Input  :  _instance   the instance object to destroy
712  *
713  *  Output :  Error code.
714  *
715  ******************************************************************/
716 
Instance_Reset(PInstance ins,Bool debug)717   TT_Error  Instance_Reset( PInstance  ins,
718                             Bool       debug )
719   {
720     TT_Error  error;
721     Int       i;
722     PFace     face = ins->face;
723     PExecution_Context exec = ins->face->font->exec;
724 
725     if ( !ins )
726       return TT_Err_Invalid_Instance_Handle;
727 
728     if ( ins->valid )
729       return TT_Err_Ok;
730 
731     if ( ins->metrics.x_ppem < 1 ||
732          ins->metrics.y_ppem < 1 )
733       return TT_Err_Invalid_PPem;
734 
735     /* compute new transformation */
736     if ( ins->metrics.x_ppem >= ins->metrics.y_ppem )
737     {
738       ins->metrics.scale1  = ins->metrics.x_scale1;
739       ins->metrics.scale2  = ins->metrics.x_scale2;
740       ins->metrics.ppem    = ins->metrics.x_ppem;
741       ins->metrics.x_ratio = 1 << 16;
742       ins->metrics.y_ratio = MulDiv_Round( ins->metrics.y_ppem,
743                                            0x10000,
744                                            ins->metrics.x_ppem );
745     }
746     else
747     {
748       ins->metrics.scale1  = ins->metrics.y_scale1;
749       ins->metrics.scale2  = ins->metrics.y_scale2;
750       ins->metrics.ppem    = ins->metrics.y_ppem;
751       ins->metrics.x_ratio = MulDiv_Round( ins->metrics.x_ppem,
752                                            0x10000,
753                                            ins->metrics.y_ppem );
754       ins->metrics.y_ratio = 1 << 16;
755     }
756 
757     /* Scale the cvt values to the new ppem.          */
758     /* We use by default the y ppem to scale the CVT. */
759 
760     for ( i = 0; i < ins->cvtSize; i++ )
761       ins->cvt[i] = MulDiv_Round( face->cvt[i],
762                                   ins->metrics.scale1,
763                                   ins->metrics.scale2 );
764 
765     ins->GS = Default_GraphicsState;
766 
767     /* get execution context and run prep program */
768 
769     Context_Load( exec, ins );
770 
771     Set_CodeRange( exec,
772                    TT_CodeRange_Cvt,
773                    face->cvtProgram,
774                    face->cvtPgmSize );
775 
776     Clear_CodeRange( exec, TT_CodeRange_Glyph );
777 
778     for ( i = 0; i < exec->storeSize; i++ )
779       exec->storage[i] = 0;
780 
781     exec->instruction_trap = FALSE;
782 
783     exec->top     = 0;
784     exec->callTop = 0;
785 
786     /* All twilight points are originally zero */
787 
788     for ( i = 0; i < exec->twilight.n_points; i++ )
789     {
790       exec->twilight.org_x[i] = 0;
791       exec->twilight.org_y[i] = 0;
792       exec->twilight.cur_x[i] = 0;
793       exec->twilight.cur_y[i] = 0;
794     }
795 
796     if ( face->cvtPgmSize > 0 )
797     {
798       error = Goto_CodeRange( exec, TT_CodeRange_Cvt, 0 );
799       if (error)
800         goto Fin;
801 
802       error = RunIns( exec );
803       Unset_CodeRange(exec);
804     }
805     else
806       error = TT_Err_Ok;
807 
808     ins->GS = exec->GS;
809     /* save default graphics state */
810 
811   Fin:
812     Context_Save( exec, ins );
813 
814     if ( !error )
815       ins->valid = TRUE;
816 
817     return error;
818   }
819 
820 
821 /*******************************************************************
822  *                                                                 *
823  *                         FACE  FUNCTIONS                         *
824  *                                                                 *
825  *                                                                 *
826  *******************************************************************/
827 
828 /*******************************************************************
829  *
830  *  Function    :  Face_Destroy
831  *
832  *  Description :  The face object destructor.
833  *
834  *  Input  :  _face   typeless pointer to the face object to destroy
835  *
836  *  Output :  Error code.
837  *
838  ******************************************************************/
839 
Face_Destroy(PFace face)840   TT_Error  Face_Destroy( PFace face )
841   {
842     ttfMemory *mem = face->font->tti->ttf_memory;
843     if ( !face )
844       return TT_Err_Ok;
845 
846     /* freeing the CVT */
847     FREE( face->cvt );
848     face->cvtSize = 0;
849 
850     /* freeing the programs */
851     FREE( face->fontProgram );
852     FREE( face->cvtProgram );
853     face->fontPgmSize = 0;
854     face->cvtPgmSize  = 0;
855 
856     return TT_Err_Ok;
857   }
858 
859 
860 /*******************************************************************
861  *
862  *  Function    :  Face_Create
863  *
864  *  Description :  The face object constructor.
865  *
866  *  Input  :  _face    face record to build
867  *            _input   input stream where to load font data
868  *
869  *  Output :  Error code.
870  *
871  *  NOTE : The input stream is kept in the face object.  The
872  *         caller shouldn't destroy it after calling Face_Create().
873  *
874  ******************************************************************/
875 
876 #define LOAD_( table ) \
877           ( error = Load_TrueType_##table (face) )
878 
879 
Face_Create(PFace face)880   TT_Error  Face_Create( PFace  face)
881   {
882     TT_Error      error;
883 
884     /* Load tables */
885 
886     if ( /*LOAD_(Header)                      ||*/
887          LOAD_(MaxProfile)                  ||
888          /*LOAD_(Locations)                   ||*/
889          /*LOAD_(CMap)                        ||*/
890          LOAD_(CVT)                         ||
891          /*LOAD_(Horizontal_Header)           ||*/
892          LOAD_(Programs)
893          /*LOAD_(HMTX)                        ||*/
894          /*LOAD_(Gasp)                        ||*/
895          /*LOAD_(Names)                       ||*/
896          /*LOAD_(OS2)                         ||*/
897          /*LOAD_(PostScript)                  ||*/
898          /*LOAD_(Hdmx)                        */
899         )
900       goto Fail;
901 
902     return TT_Err_Ok;
903 
904   Fail :
905     Face_Destroy( face );
906     return error;
907   }
908 
909 
910 
911 
912 /*******************************************************************
913  *
914  *  Function    :  Scale_X
915  *
916  *  Description :  scale an horizontal distance from font
917  *                 units to 26.6 pixels
918  *
919  *  Input  :  metrics  pointer to metrics
920  *            x        value to scale
921  *
922  *  Output :  scaled value
923  *
924  ******************************************************************/
925 
Scale_X(PIns_Metrics metrics,TT_Pos x)926  TT_Pos  Scale_X( PIns_Metrics  metrics, TT_Pos  x )
927  {
928    return MulDiv_Round( x, metrics->x_scale1, metrics->x_scale2 );
929  }
930 
931 /*******************************************************************
932  *
933  *  Function    :  Scale_Y
934  *
935  *  Description :  scale a vertical distance from font
936  *                 units to 26.6 pixels
937  *
938  *  Input  :  metrics  pointer to metrics
939  *            y        value to scale
940  *
941  *  Output :  scaled value
942  *
943  ******************************************************************/
944 
Scale_Y(PIns_Metrics metrics,TT_Pos y)945  TT_Pos  Scale_Y( PIns_Metrics  metrics, TT_Pos  y )
946  {
947    return MulDiv_Round( y, metrics->y_scale1, metrics->y_scale2 );
948  }
949 
950