• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  cf2ft.c                                                                */
4 /*                                                                         */
5 /*    FreeType Glue Component to Adobe's Interpreter (body).               */
6 /*                                                                         */
7 /*  Copyright 2013-2014 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 "cf2ft.h"
40 #include FT_INTERNAL_DEBUG_H
41 
42 #include "cf2font.h"
43 #include "cf2error.h"
44 
45 
46 #define CF2_MAX_SIZE  cf2_intToFixed( 2000 )    /* max ppem */
47 
48 
49   /*
50    * This check should avoid most internal overflow cases.  Clients should
51    * generally respond to `Glyph_Too_Big' by getting a glyph outline
52    * at EM size, scaling it and filling it as a graphics operation.
53    *
54    */
55   static FT_Error
cf2_checkTransform(const CF2_Matrix * transform,CF2_Int unitsPerEm)56   cf2_checkTransform( const CF2_Matrix*  transform,
57                       CF2_Int            unitsPerEm )
58   {
59     CF2_Fixed  maxScale;
60 
61 
62     FT_ASSERT( unitsPerEm > 0 );
63 
64     if ( transform->a <= 0 || transform->d <= 0 )
65       return FT_THROW( Invalid_Size_Handle );
66 
67     FT_ASSERT( transform->b == 0 && transform->c == 0 );
68     FT_ASSERT( transform->tx == 0 && transform->ty == 0 );
69 
70     if ( unitsPerEm > 0x7FFF )
71       return FT_THROW( Glyph_Too_Big );
72 
73     maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) );
74 
75     if ( transform->a > maxScale || transform->d > maxScale )
76       return FT_THROW( Glyph_Too_Big );
77 
78     return FT_Err_Ok;
79   }
80 
81 
82   static void
cf2_setGlyphWidth(CF2_Outline outline,CF2_Fixed width)83   cf2_setGlyphWidth( CF2_Outline  outline,
84                      CF2_Fixed    width )
85   {
86     CFF_Decoder*  decoder = outline->decoder;
87 
88 
89     FT_ASSERT( decoder );
90 
91     decoder->glyph_width = cf2_fixedToInt( width );
92   }
93 
94 
95   /* Clean up font instance. */
96   static void
cf2_free_instance(void * ptr)97   cf2_free_instance( void*  ptr )
98   {
99     CF2_Font  font = (CF2_Font)ptr;
100 
101 
102     if ( font )
103     {
104       FT_Memory  memory = font->memory;
105 
106 
107       FT_FREE( font->blend.lastNDV );
108       FT_FREE( font->blend.BV );
109     }
110   }
111 
112 
113   /********************************************/
114   /*                                          */
115   /* functions for handling client outline;   */
116   /* FreeType uses coordinates in 26.6 format */
117   /*                                          */
118   /********************************************/
119 
120   static void
cf2_builder_moveTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)121   cf2_builder_moveTo( CF2_OutlineCallbacks      callbacks,
122                       const CF2_CallbackParams  params )
123   {
124     /* downcast the object pointer */
125     CF2_Outline   outline = (CF2_Outline)callbacks;
126     CFF_Builder*  builder;
127 
128     (void)params;        /* only used in debug mode */
129 
130 
131     FT_ASSERT( outline && outline->decoder );
132     FT_ASSERT( params->op == CF2_PathOpMoveTo );
133 
134     builder = &outline->decoder->builder;
135 
136     /* note: two successive moves simply close the contour twice */
137     cff_builder_close_contour( builder );
138     builder->path_begun = 0;
139   }
140 
141 
142   static void
cf2_builder_lineTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)143   cf2_builder_lineTo( CF2_OutlineCallbacks      callbacks,
144                       const CF2_CallbackParams  params )
145   {
146     FT_Error  error;
147 
148     /* downcast the object pointer */
149     CF2_Outline   outline = (CF2_Outline)callbacks;
150     CFF_Builder*  builder;
151 
152 
153     FT_ASSERT( outline && outline->decoder );
154     FT_ASSERT( params->op == CF2_PathOpLineTo );
155 
156     builder = &outline->decoder->builder;
157 
158     if ( !builder->path_begun )
159     {
160       /* record the move before the line; also check points and set */
161       /* `path_begun'                                               */
162       error = cff_builder_start_point( builder,
163                                        params->pt0.x,
164                                        params->pt0.y );
165       if ( error )
166       {
167         if ( !*callbacks->error )
168           *callbacks->error =  error;
169         return;
170       }
171     }
172 
173     /* `cff_builder_add_point1' includes a check_points call for one point */
174     error = cff_builder_add_point1( builder,
175                                     params->pt1.x,
176                                     params->pt1.y );
177     if ( error )
178     {
179       if ( !*callbacks->error )
180         *callbacks->error =  error;
181       return;
182     }
183   }
184 
185 
186   static void
cf2_builder_cubeTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)187   cf2_builder_cubeTo( CF2_OutlineCallbacks      callbacks,
188                       const CF2_CallbackParams  params )
189   {
190     FT_Error  error;
191 
192     /* downcast the object pointer */
193     CF2_Outline   outline = (CF2_Outline)callbacks;
194     CFF_Builder*  builder;
195 
196 
197     FT_ASSERT( outline && outline->decoder );
198     FT_ASSERT( params->op == CF2_PathOpCubeTo );
199 
200     builder = &outline->decoder->builder;
201 
202     if ( !builder->path_begun )
203     {
204       /* record the move before the line; also check points and set */
205       /* `path_begun'                                               */
206       error = cff_builder_start_point( builder,
207                                        params->pt0.x,
208                                        params->pt0.y );
209       if ( error )
210       {
211         if ( !*callbacks->error )
212           *callbacks->error =  error;
213         return;
214       }
215     }
216 
217     /* prepare room for 3 points: 2 off-curve, 1 on-curve */
218     error = cff_check_points( builder, 3 );
219     if ( error )
220     {
221       if ( !*callbacks->error )
222         *callbacks->error =  error;
223       return;
224     }
225 
226     cff_builder_add_point( builder,
227                            params->pt1.x,
228                            params->pt1.y, 0 );
229     cff_builder_add_point( builder,
230                            params->pt2.x,
231                            params->pt2.y, 0 );
232     cff_builder_add_point( builder,
233                            params->pt3.x,
234                            params->pt3.y, 1 );
235   }
236 
237 
238   static void
cf2_outline_init(CF2_Outline outline,FT_Memory memory,FT_Error * error)239   cf2_outline_init( CF2_Outline  outline,
240                     FT_Memory    memory,
241                     FT_Error*    error )
242   {
243     FT_ZERO( outline );
244 
245     outline->root.memory = memory;
246     outline->root.error  = error;
247 
248     outline->root.moveTo = cf2_builder_moveTo;
249     outline->root.lineTo = cf2_builder_lineTo;
250     outline->root.cubeTo = cf2_builder_cubeTo;
251   }
252 
253 
254   /* get scaling and hint flag from GlyphSlot */
255   static void
cf2_getScaleAndHintFlag(CFF_Decoder * decoder,CF2_Fixed * x_scale,CF2_Fixed * y_scale,FT_Bool * hinted,FT_Bool * scaled)256   cf2_getScaleAndHintFlag( CFF_Decoder*  decoder,
257                            CF2_Fixed*    x_scale,
258                            CF2_Fixed*    y_scale,
259                            FT_Bool*      hinted,
260                            FT_Bool*      scaled )
261   {
262     FT_ASSERT( decoder && decoder->builder.glyph );
263 
264     /* note: FreeType scale includes a factor of 64 */
265     *hinted = decoder->builder.glyph->hint;
266     *scaled = decoder->builder.glyph->scaled;
267 
268     if ( *hinted )
269     {
270       *x_scale = ( decoder->builder.glyph->x_scale + 32 ) / 64;
271       *y_scale = ( decoder->builder.glyph->y_scale + 32 ) / 64;
272     }
273     else
274     {
275       /* for unhinted outlines, `cff_slot_load' does the scaling, */
276       /* thus render at `unity' scale                             */
277 
278       *x_scale = 0x0400;   /* 1/64 as 16.16 */
279       *y_scale = 0x0400;
280     }
281   }
282 
283 
284   /* get units per em from `FT_Face' */
285   /* TODO: should handle font matrix concatenation? */
286   static FT_UShort
cf2_getUnitsPerEm(CFF_Decoder * decoder)287   cf2_getUnitsPerEm( CFF_Decoder*  decoder )
288   {
289     FT_ASSERT( decoder && decoder->builder.face );
290     FT_ASSERT( decoder->builder.face->root.units_per_EM );
291 
292     return decoder->builder.face->root.units_per_EM;
293   }
294 
295 
296   /* Main entry point: Render one glyph. */
297   FT_LOCAL_DEF( FT_Error )
cf2_decoder_parse_charstrings(CFF_Decoder * decoder,FT_Byte * charstring_base,FT_ULong charstring_len)298   cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
299                                  FT_Byte*      charstring_base,
300                                  FT_ULong      charstring_len )
301   {
302     FT_Memory  memory;
303     FT_Error   error = FT_Err_Ok;
304     CF2_Font   font;
305 
306 
307     FT_ASSERT( decoder && decoder->cff );
308 
309     memory = decoder->builder.memory;
310 
311     /* CF2 data is saved here across glyphs */
312     font = (CF2_Font)decoder->cff->cf2_instance.data;
313 
314     /* on first glyph, allocate instance structure */
315     if ( !decoder->cff->cf2_instance.data )
316     {
317       decoder->cff->cf2_instance.finalizer =
318         (FT_Generic_Finalizer)cf2_free_instance;
319 
320       if ( FT_ALLOC( decoder->cff->cf2_instance.data,
321                      sizeof ( CF2_FontRec ) ) )
322         return FT_THROW( Out_Of_Memory );
323 
324       font = (CF2_Font)decoder->cff->cf2_instance.data;
325 
326       font->memory = memory;
327 
328       /* initialize a client outline, to be shared by each glyph rendered */
329       cf2_outline_init( &font->outline, font->memory, &font->error );
330     }
331 
332     /* save decoder; it is a stack variable and will be different on each */
333     /* call                                                               */
334     font->decoder         = decoder;
335     font->outline.decoder = decoder;
336 
337     {
338       /* build parameters for Adobe engine */
339 
340       CFF_Builder*  builder = &decoder->builder;
341       CFF_Driver    driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
342 
343       /* local error */
344       FT_Error       error2 = FT_Err_Ok;
345       CF2_BufferRec  buf;
346       CF2_Matrix     transform;
347       CF2_F16Dot16   glyphWidth;
348 
349       FT_Bool  hinted;
350       FT_Bool  scaled;
351 
352 
353       /* FreeType has already looked up the GID; convert to         */
354       /* `RegionBuffer', assuming that the input has been validated */
355       FT_ASSERT( charstring_base + charstring_len >= charstring_base );
356 
357       FT_ZERO( &buf );
358       buf.start =
359       buf.ptr   = charstring_base;
360       buf.end   = charstring_base + charstring_len;
361 
362       FT_ZERO( &transform );
363 
364       cf2_getScaleAndHintFlag( decoder,
365                                &transform.a,
366                                &transform.d,
367                                &hinted,
368                                &scaled );
369 
370       /* copy isCFF2 boolean from TT_Face to CF2_Font */
371       font->isCFF2 = builder->face->isCFF2;
372 
373       font->renderingFlags = 0;
374       if ( hinted )
375         font->renderingFlags |= CF2_FlagsHinted;
376       if ( scaled && !driver->no_stem_darkening )
377         font->renderingFlags |= CF2_FlagsDarkened;
378 
379       font->darkenParams[0] = driver->darken_params[0];
380       font->darkenParams[1] = driver->darken_params[1];
381       font->darkenParams[2] = driver->darken_params[2];
382       font->darkenParams[3] = driver->darken_params[3];
383       font->darkenParams[4] = driver->darken_params[4];
384       font->darkenParams[5] = driver->darken_params[5];
385       font->darkenParams[6] = driver->darken_params[6];
386       font->darkenParams[7] = driver->darken_params[7];
387 
388       /* now get an outline for this glyph;      */
389       /* also get units per em to validate scale */
390       font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );
391 
392       if ( scaled )
393       {
394         error2 = cf2_checkTransform( &transform, font->unitsPerEm );
395         if ( error2 )
396           return error2;
397       }
398 
399       error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth );
400       if ( error2 )
401         return FT_ERR( Invalid_File_Format );
402 
403       cf2_setGlyphWidth( &font->outline, glyphWidth );
404 
405       return FT_Err_Ok;
406     }
407   }
408 
409 
410   /* get pointer to current FreeType subfont (based on current glyphID) */
411   FT_LOCAL_DEF( CFF_SubFont )
cf2_getSubfont(CFF_Decoder * decoder)412   cf2_getSubfont( CFF_Decoder*  decoder )
413   {
414     FT_ASSERT( decoder && decoder->current_subfont );
415 
416     return decoder->current_subfont;
417   }
418 
419 
420   /* get pointer to VStore structure */
421   FT_LOCAL_DEF( CFF_VStore )
cf2_getVStore(CFF_Decoder * decoder)422   cf2_getVStore( CFF_Decoder*  decoder )
423   {
424     FT_ASSERT( decoder && decoder->cff );
425 
426     return &decoder->cff->vstore;
427   }
428 
429 
430   /* get maxstack value from CFF2 Top DICT */
431   FT_LOCAL_DEF( FT_UInt )
cf2_getMaxstack(CFF_Decoder * decoder)432   cf2_getMaxstack( CFF_Decoder*  decoder )
433   {
434     FT_ASSERT( decoder && decoder->cff );
435 
436     return decoder->cff->top_font.font_dict.maxstack;
437   }
438 
439 
440 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
441   /* Get normalized design vector for current render request; */
442   /* return pointer and length.                               */
443   /*                                                          */
444   /* Note: Uses FT_Fixed not CF2_Fixed for the vector.        */
445   FT_LOCAL_DEF( FT_Error )
cf2_getNormalizedVector(CFF_Decoder * decoder,CF2_UInt * len,FT_Fixed ** vec)446   cf2_getNormalizedVector( CFF_Decoder*  decoder,
447                            CF2_UInt     *len,
448                            FT_Fixed*    *vec )
449   {
450     FT_ASSERT( decoder && decoder->builder.face );
451     FT_ASSERT( vec && len );
452 
453     return cff_get_var_blend( decoder->builder.face, len, vec, NULL );
454   }
455 #endif
456 
457 
458   /* get `y_ppem' from `CFF_Size' */
459   FT_LOCAL_DEF( CF2_Fixed )
cf2_getPpemY(CFF_Decoder * decoder)460   cf2_getPpemY( CFF_Decoder*  decoder )
461   {
462     FT_ASSERT( decoder                          &&
463                decoder->builder.face            &&
464                decoder->builder.face->root.size );
465 
466     /*
467      * Note that `y_ppem' can be zero if there wasn't a call to
468      * `FT_Set_Char_Size' or something similar.  However, this isn't a
469      * problem since we come to this place in the code only if
470      * FT_LOAD_NO_SCALE is set (the other case gets caught by
471      * `cf2_checkTransform').  The ppem value is needed to compute the stem
472      * darkening, which is disabled for getting the unscaled outline.
473      *
474      */
475     return cf2_intToFixed(
476              decoder->builder.face->root.size->metrics.y_ppem );
477   }
478 
479 
480   /* get standard stem widths for the current subfont; */
481   /* FreeType stores these as integer font units       */
482   /* (note: variable names seem swapped)               */
483   FT_LOCAL_DEF( CF2_Fixed )
cf2_getStdVW(CFF_Decoder * decoder)484   cf2_getStdVW( CFF_Decoder*  decoder )
485   {
486     FT_ASSERT( decoder && decoder->current_subfont );
487 
488     return cf2_intToFixed(
489              decoder->current_subfont->private_dict.standard_height );
490   }
491 
492 
493   FT_LOCAL_DEF( CF2_Fixed )
cf2_getStdHW(CFF_Decoder * decoder)494   cf2_getStdHW( CFF_Decoder*  decoder )
495   {
496     FT_ASSERT( decoder && decoder->current_subfont );
497 
498     return cf2_intToFixed(
499              decoder->current_subfont->private_dict.standard_width );
500   }
501 
502 
503   /* note: FreeType stores 1000 times the actual value for `BlueScale' */
504   FT_LOCAL_DEF( void )
cf2_getBlueMetrics(CFF_Decoder * decoder,CF2_Fixed * blueScale,CF2_Fixed * blueShift,CF2_Fixed * blueFuzz)505   cf2_getBlueMetrics( CFF_Decoder*  decoder,
506                       CF2_Fixed*    blueScale,
507                       CF2_Fixed*    blueShift,
508                       CF2_Fixed*    blueFuzz )
509   {
510     FT_ASSERT( decoder && decoder->current_subfont );
511 
512     *blueScale = FT_DivFix(
513                    decoder->current_subfont->private_dict.blue_scale,
514                    cf2_intToFixed( 1000 ) );
515     *blueShift = cf2_intToFixed(
516                    decoder->current_subfont->private_dict.blue_shift );
517     *blueFuzz  = cf2_intToFixed(
518                    decoder->current_subfont->private_dict.blue_fuzz );
519   }
520 
521 
522   /* get blue values counts and arrays; the FreeType parser has validated */
523   /* the counts and verified that each is an even number                  */
524   FT_LOCAL_DEF( void )
cf2_getBlueValues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)525   cf2_getBlueValues( CFF_Decoder*  decoder,
526                      size_t*       count,
527                      FT_Pos*      *data )
528   {
529     FT_ASSERT( decoder && decoder->current_subfont );
530 
531     *count = decoder->current_subfont->private_dict.num_blue_values;
532     *data  = (FT_Pos*)
533                &decoder->current_subfont->private_dict.blue_values;
534   }
535 
536 
537   FT_LOCAL_DEF( void )
cf2_getOtherBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)538   cf2_getOtherBlues( CFF_Decoder*  decoder,
539                      size_t*       count,
540                      FT_Pos*      *data )
541   {
542     FT_ASSERT( decoder && decoder->current_subfont );
543 
544     *count = decoder->current_subfont->private_dict.num_other_blues;
545     *data  = (FT_Pos*)
546                &decoder->current_subfont->private_dict.other_blues;
547   }
548 
549 
550   FT_LOCAL_DEF( void )
cf2_getFamilyBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)551   cf2_getFamilyBlues( CFF_Decoder*  decoder,
552                       size_t*       count,
553                       FT_Pos*      *data )
554   {
555     FT_ASSERT( decoder && decoder->current_subfont );
556 
557     *count = decoder->current_subfont->private_dict.num_family_blues;
558     *data  = (FT_Pos*)
559                &decoder->current_subfont->private_dict.family_blues;
560   }
561 
562 
563   FT_LOCAL_DEF( void )
cf2_getFamilyOtherBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)564   cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
565                            size_t*       count,
566                            FT_Pos*      *data )
567   {
568     FT_ASSERT( decoder && decoder->current_subfont );
569 
570     *count = decoder->current_subfont->private_dict.num_family_other_blues;
571     *data  = (FT_Pos*)
572                &decoder->current_subfont->private_dict.family_other_blues;
573   }
574 
575 
576   FT_LOCAL_DEF( CF2_Int )
cf2_getLanguageGroup(CFF_Decoder * decoder)577   cf2_getLanguageGroup( CFF_Decoder*  decoder )
578   {
579     FT_ASSERT( decoder && decoder->current_subfont );
580 
581     return decoder->current_subfont->private_dict.language_group;
582   }
583 
584 
585   /* convert unbiased subroutine index to `CF2_Buffer' and */
586   /* return 0 on success                                   */
587   FT_LOCAL_DEF( CF2_Int )
cf2_initGlobalRegionBuffer(CFF_Decoder * decoder,CF2_Int subrNum,CF2_Buffer buf)588   cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
589                               CF2_Int       subrNum,
590                               CF2_Buffer    buf )
591   {
592     CF2_UInt  idx;
593 
594 
595     FT_ASSERT( decoder );
596 
597     FT_ZERO( buf );
598 
599     idx = (CF2_UInt)( subrNum + decoder->globals_bias );
600     if ( idx >= decoder->num_globals )
601       return TRUE;     /* error */
602 
603     FT_ASSERT( decoder->globals );
604 
605     buf->start =
606     buf->ptr   = decoder->globals[idx];
607     buf->end   = decoder->globals[idx + 1];
608 
609     return FALSE;      /* success */
610   }
611 
612 
613   /* convert AdobeStandardEncoding code to CF2_Buffer; */
614   /* used for seac component                           */
615   FT_LOCAL_DEF( FT_Error )
cf2_getSeacComponent(CFF_Decoder * decoder,CF2_Int code,CF2_Buffer buf)616   cf2_getSeacComponent( CFF_Decoder*  decoder,
617                         CF2_Int       code,
618                         CF2_Buffer    buf )
619   {
620     CF2_Int   gid;
621     FT_Byte*  charstring;
622     FT_ULong  len;
623     FT_Error  error;
624 
625 
626     FT_ASSERT( decoder );
627 
628     FT_ZERO( buf );
629 
630 #ifdef FT_CONFIG_OPTION_INCREMENTAL
631     /* Incremental fonts don't necessarily have valid charsets.        */
632     /* They use the character code, not the glyph index, in this case. */
633     if ( decoder->builder.face->root.internal->incremental_interface )
634       gid = code;
635     else
636 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
637     {
638       gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code );
639       if ( gid < 0 )
640         return FT_THROW( Invalid_Glyph_Format );
641     }
642 
643     error = cff_get_glyph_data( decoder->builder.face,
644                                 (CF2_UInt)gid,
645                                 &charstring,
646                                 &len );
647     /* TODO: for now, just pass the FreeType error through */
648     if ( error )
649       return error;
650 
651     /* assume input has been validated */
652     FT_ASSERT( charstring + len >= charstring );
653 
654     buf->start = charstring;
655     buf->end   = charstring + len;
656     buf->ptr   = buf->start;
657 
658     return FT_Err_Ok;
659   }
660 
661 
662   FT_LOCAL_DEF( void )
cf2_freeSeacComponent(CFF_Decoder * decoder,CF2_Buffer buf)663   cf2_freeSeacComponent( CFF_Decoder*  decoder,
664                          CF2_Buffer    buf )
665   {
666     FT_ASSERT( decoder );
667 
668     cff_free_glyph_data( decoder->builder.face,
669                          (FT_Byte**)&buf->start,
670                          (FT_ULong)( buf->end - buf->start ) );
671   }
672 
673 
674   FT_LOCAL_DEF( CF2_Int )
cf2_initLocalRegionBuffer(CFF_Decoder * decoder,CF2_Int subrNum,CF2_Buffer buf)675   cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
676                              CF2_Int       subrNum,
677                              CF2_Buffer    buf )
678   {
679     CF2_UInt  idx;
680 
681 
682     FT_ASSERT( decoder );
683 
684     FT_ZERO( buf );
685 
686     idx = (CF2_UInt)( subrNum + decoder->locals_bias );
687     if ( idx >= decoder->num_locals )
688       return TRUE;     /* error */
689 
690     FT_ASSERT( decoder->locals );
691 
692     buf->start =
693     buf->ptr   = decoder->locals[idx];
694     buf->end   = decoder->locals[idx + 1];
695 
696     return FALSE;      /* success */
697   }
698 
699 
700   FT_LOCAL_DEF( CF2_Fixed )
cf2_getDefaultWidthX(CFF_Decoder * decoder)701   cf2_getDefaultWidthX( CFF_Decoder*  decoder )
702   {
703     FT_ASSERT( decoder && decoder->current_subfont );
704 
705     return cf2_intToFixed(
706              decoder->current_subfont->private_dict.default_width );
707   }
708 
709 
710   FT_LOCAL_DEF( CF2_Fixed )
cf2_getNominalWidthX(CFF_Decoder * decoder)711   cf2_getNominalWidthX( CFF_Decoder*  decoder )
712   {
713     FT_ASSERT( decoder && decoder->current_subfont );
714 
715     return cf2_intToFixed(
716              decoder->current_subfont->private_dict.nominal_width );
717   }
718 
719 
720   FT_LOCAL_DEF( void )
cf2_outline_reset(CF2_Outline outline)721   cf2_outline_reset( CF2_Outline  outline )
722   {
723     CFF_Decoder*  decoder = outline->decoder;
724 
725 
726     FT_ASSERT( decoder );
727 
728     outline->root.windingMomentum = 0;
729 
730     FT_GlyphLoader_Rewind( decoder->builder.loader );
731   }
732 
733 
734   FT_LOCAL_DEF( void )
cf2_outline_close(CF2_Outline outline)735   cf2_outline_close( CF2_Outline  outline )
736   {
737     CFF_Decoder*  decoder = outline->decoder;
738 
739 
740     FT_ASSERT( decoder );
741 
742     cff_builder_close_contour( &decoder->builder );
743 
744     FT_GlyphLoader_Add( decoder->builder.loader );
745   }
746 
747 
748 /* END */
749