cf2ft.c revision 9c745321260bb728ab1cd1c8fd5f075854b2ad49
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
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
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
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      (void)memory;
108    }
109  }
110
111
112  /********************************************/
113  /*                                          */
114  /* functions for handling client outline;   */
115  /* FreeType uses coordinates in 26.6 format */
116  /*                                          */
117  /********************************************/
118
119  static void
120  cf2_builder_moveTo( CF2_OutlineCallbacks      callbacks,
121                      const CF2_CallbackParams  params )
122  {
123    /* downcast the object pointer */
124    CF2_Outline   outline = (CF2_Outline)callbacks;
125    CFF_Builder*  builder;
126
127    (void)params;        /* only used in debug mode */
128
129
130    FT_ASSERT( outline && outline->decoder );
131    FT_ASSERT( params->op == CF2_PathOpMoveTo );
132
133    builder = &outline->decoder->builder;
134
135    /* note: two successive moves simply close the contour twice */
136    cff_builder_close_contour( builder );
137    builder->path_begun = 0;
138  }
139
140
141  static void
142  cf2_builder_lineTo( CF2_OutlineCallbacks      callbacks,
143                      const CF2_CallbackParams  params )
144  {
145    /* downcast the object pointer */
146    CF2_Outline   outline = (CF2_Outline)callbacks;
147    CFF_Builder*  builder;
148
149
150    FT_ASSERT( outline && outline->decoder );
151    FT_ASSERT( params->op == CF2_PathOpLineTo );
152
153    builder = &outline->decoder->builder;
154
155    if ( !builder->path_begun )
156    {
157      /* record the move before the line; also check points and set */
158      /* `path_begun'                                               */
159      cff_builder_start_point( builder,
160                               params->pt0.x,
161                               params->pt0.y );
162    }
163
164    /* `cff_builder_add_point1' includes a check_points call for one point */
165    cff_builder_add_point1( builder,
166                            params->pt1.x,
167                            params->pt1.y );
168  }
169
170
171  static void
172  cf2_builder_cubeTo( CF2_OutlineCallbacks      callbacks,
173                      const CF2_CallbackParams  params )
174  {
175    /* downcast the object pointer */
176    CF2_Outline   outline = (CF2_Outline)callbacks;
177    CFF_Builder*  builder;
178
179
180    FT_ASSERT( outline && outline->decoder );
181    FT_ASSERT( params->op == CF2_PathOpCubeTo );
182
183    builder = &outline->decoder->builder;
184
185    if ( !builder->path_begun )
186    {
187      /* record the move before the line; also check points and set */
188      /* `path_begun'                                               */
189      cff_builder_start_point( builder,
190                               params->pt0.x,
191                               params->pt0.y );
192    }
193
194    /* prepare room for 3 points: 2 off-curve, 1 on-curve */
195    cff_check_points( builder, 3 );
196
197    cff_builder_add_point( builder,
198                           params->pt1.x,
199                           params->pt1.y, 0 );
200    cff_builder_add_point( builder,
201                           params->pt2.x,
202                           params->pt2.y, 0 );
203    cff_builder_add_point( builder,
204                           params->pt3.x,
205                           params->pt3.y, 1 );
206  }
207
208
209  static void
210  cf2_outline_init( CF2_Outline  outline,
211                    FT_Memory    memory,
212                    FT_Error*    error )
213  {
214    FT_MEM_ZERO( outline, sizeof ( CF2_OutlineRec ) );
215
216    outline->root.memory = memory;
217    outline->root.error  = error;
218
219    outline->root.moveTo = cf2_builder_moveTo;
220    outline->root.lineTo = cf2_builder_lineTo;
221    outline->root.cubeTo = cf2_builder_cubeTo;
222  }
223
224
225  /* get scaling and hint flag from GlyphSlot */
226  static void
227  cf2_getScaleAndHintFlag( CFF_Decoder*  decoder,
228                           CF2_Fixed*    x_scale,
229                           CF2_Fixed*    y_scale,
230                           FT_Bool*      hinted,
231                           FT_Bool*      scaled )
232  {
233    FT_ASSERT( decoder && decoder->builder.glyph );
234
235    /* note: FreeType scale includes a factor of 64 */
236    *hinted = decoder->builder.glyph->hint;
237    *scaled = decoder->builder.glyph->scaled;
238
239    if ( *hinted )
240    {
241      *x_scale = ( decoder->builder.glyph->x_scale + 32 ) / 64;
242      *y_scale = ( decoder->builder.glyph->y_scale + 32 ) / 64;
243    }
244    else
245    {
246      /* for unhinted outlines, `cff_slot_load' does the scaling, */
247      /* thus render at `unity' scale                             */
248
249      *x_scale = 0x0400;   /* 1/64 as 16.16 */
250      *y_scale = 0x0400;
251    }
252  }
253
254
255  /* get units per em from `FT_Face' */
256  /* TODO: should handle font matrix concatenation? */
257  static FT_UShort
258  cf2_getUnitsPerEm( CFF_Decoder*  decoder )
259  {
260    FT_ASSERT( decoder && decoder->builder.face );
261    FT_ASSERT( decoder->builder.face->root.units_per_EM );
262
263    return decoder->builder.face->root.units_per_EM;
264  }
265
266
267  /* Main entry point: Render one glyph. */
268  FT_LOCAL_DEF( FT_Error )
269  cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
270                                 FT_Byte*      charstring_base,
271                                 FT_ULong      charstring_len )
272  {
273    FT_Memory  memory;
274    FT_Error   error = FT_Err_Ok;
275    CF2_Font   font;
276
277
278    FT_ASSERT( decoder && decoder->cff );
279
280    memory = decoder->builder.memory;
281
282    /* CF2 data is saved here across glyphs */
283    font = (CF2_Font)decoder->cff->cf2_instance.data;
284
285    /* on first glyph, allocate instance structure */
286    if ( decoder->cff->cf2_instance.data == NULL )
287    {
288      decoder->cff->cf2_instance.finalizer =
289        (FT_Generic_Finalizer)cf2_free_instance;
290
291      if ( FT_ALLOC( decoder->cff->cf2_instance.data,
292                     sizeof ( CF2_FontRec ) ) )
293        return FT_THROW( Out_Of_Memory );
294
295      font = (CF2_Font)decoder->cff->cf2_instance.data;
296
297      font->memory = memory;
298
299      /* initialize a client outline, to be shared by each glyph rendered */
300      cf2_outline_init( &font->outline, font->memory, &font->error );
301    }
302
303    /* save decoder; it is a stack variable and will be different on each */
304    /* call                                                               */
305    font->decoder         = decoder;
306    font->outline.decoder = decoder;
307
308    {
309      /* build parameters for Adobe engine */
310
311      CFF_Builder*  builder = &decoder->builder;
312      CFF_Driver    driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
313
314      /* local error */
315      FT_Error       error2 = FT_Err_Ok;
316      CF2_BufferRec  buf;
317      CF2_Matrix     transform;
318      CF2_F16Dot16   glyphWidth;
319
320      FT_Bool  hinted;
321      FT_Bool  scaled;
322
323
324      /* FreeType has already looked up the GID; convert to         */
325      /* `RegionBuffer', assuming that the input has been validated */
326      FT_ASSERT( charstring_base + charstring_len >= charstring_base );
327
328      FT_ZERO( &buf );
329      buf.start =
330      buf.ptr   = charstring_base;
331      buf.end   = charstring_base + charstring_len;
332
333      FT_ZERO( &transform );
334
335      cf2_getScaleAndHintFlag( decoder,
336                               &transform.a,
337                               &transform.d,
338                               &hinted,
339                               &scaled );
340
341      font->renderingFlags = 0;
342      if ( hinted )
343        font->renderingFlags |= CF2_FlagsHinted;
344      if ( scaled && !driver->no_stem_darkening )
345        font->renderingFlags |= CF2_FlagsDarkened;
346
347      font->darkenParams[0] = driver->darken_params[0];
348      font->darkenParams[1] = driver->darken_params[1];
349      font->darkenParams[2] = driver->darken_params[2];
350      font->darkenParams[3] = driver->darken_params[3];
351      font->darkenParams[4] = driver->darken_params[4];
352      font->darkenParams[5] = driver->darken_params[5];
353      font->darkenParams[6] = driver->darken_params[6];
354      font->darkenParams[7] = driver->darken_params[7];
355
356      /* now get an outline for this glyph;      */
357      /* also get units per em to validate scale */
358      font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );
359
360      if ( scaled )
361      {
362        error2 = cf2_checkTransform( &transform, font->unitsPerEm );
363        if ( error2 )
364          return error2;
365      }
366
367      error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth );
368      if ( error2 )
369        return FT_ERR( Invalid_File_Format );
370
371      cf2_setGlyphWidth( &font->outline, glyphWidth );
372
373      return FT_Err_Ok;
374    }
375  }
376
377
378  /* get pointer to current FreeType subfont (based on current glyphID) */
379  FT_LOCAL_DEF( CFF_SubFont )
380  cf2_getSubfont( CFF_Decoder*  decoder )
381  {
382    FT_ASSERT( decoder && decoder->current_subfont );
383
384    return decoder->current_subfont;
385  }
386
387
388  /* get `y_ppem' from `CFF_Size' */
389  FT_LOCAL_DEF( CF2_Fixed )
390  cf2_getPpemY( CFF_Decoder*  decoder )
391  {
392    FT_ASSERT( decoder                          &&
393               decoder->builder.face            &&
394               decoder->builder.face->root.size );
395
396    /*
397     * Note that `y_ppem' can be zero if there wasn't a call to
398     * `FT_Set_Char_Size' or something similar.  However, this isn't a
399     * problem since we come to this place in the code only if
400     * FT_LOAD_NO_SCALE is set (the other case gets caught by
401     * `cf2_checkTransform').  The ppem value is needed to compute the stem
402     * darkening, which is disabled for getting the unscaled outline.
403     *
404     */
405    return cf2_intToFixed(
406             decoder->builder.face->root.size->metrics.y_ppem );
407  }
408
409
410  /* get standard stem widths for the current subfont; */
411  /* FreeType stores these as integer font units       */
412  /* (note: variable names seem swapped)               */
413  FT_LOCAL_DEF( CF2_Fixed )
414  cf2_getStdVW( CFF_Decoder*  decoder )
415  {
416    FT_ASSERT( decoder && decoder->current_subfont );
417
418    return cf2_intToFixed(
419             decoder->current_subfont->private_dict.standard_height );
420  }
421
422
423  FT_LOCAL_DEF( CF2_Fixed )
424  cf2_getStdHW( CFF_Decoder*  decoder )
425  {
426    FT_ASSERT( decoder && decoder->current_subfont );
427
428    return cf2_intToFixed(
429             decoder->current_subfont->private_dict.standard_width );
430  }
431
432
433  /* note: FreeType stores 1000 times the actual value for `BlueScale' */
434  FT_LOCAL_DEF( void )
435  cf2_getBlueMetrics( CFF_Decoder*  decoder,
436                      CF2_Fixed*    blueScale,
437                      CF2_Fixed*    blueShift,
438                      CF2_Fixed*    blueFuzz )
439  {
440    FT_ASSERT( decoder && decoder->current_subfont );
441
442    *blueScale = FT_DivFix(
443                   decoder->current_subfont->private_dict.blue_scale,
444                   cf2_intToFixed( 1000 ) );
445    *blueShift = cf2_intToFixed(
446                   decoder->current_subfont->private_dict.blue_shift );
447    *blueFuzz  = cf2_intToFixed(
448                   decoder->current_subfont->private_dict.blue_fuzz );
449  }
450
451
452  /* get blue values counts and arrays; the FreeType parser has validated */
453  /* the counts and verified that each is an even number                  */
454  FT_LOCAL_DEF( void )
455  cf2_getBlueValues( CFF_Decoder*  decoder,
456                     size_t*       count,
457                     FT_Pos*      *data )
458  {
459    FT_ASSERT( decoder && decoder->current_subfont );
460
461    *count = decoder->current_subfont->private_dict.num_blue_values;
462    *data  = (FT_Pos*)
463               &decoder->current_subfont->private_dict.blue_values;
464  }
465
466
467  FT_LOCAL_DEF( void )
468  cf2_getOtherBlues( CFF_Decoder*  decoder,
469                     size_t*       count,
470                     FT_Pos*      *data )
471  {
472    FT_ASSERT( decoder && decoder->current_subfont );
473
474    *count = decoder->current_subfont->private_dict.num_other_blues;
475    *data  = (FT_Pos*)
476               &decoder->current_subfont->private_dict.other_blues;
477  }
478
479
480  FT_LOCAL_DEF( void )
481  cf2_getFamilyBlues( CFF_Decoder*  decoder,
482                      size_t*       count,
483                      FT_Pos*      *data )
484  {
485    FT_ASSERT( decoder && decoder->current_subfont );
486
487    *count = decoder->current_subfont->private_dict.num_family_blues;
488    *data  = (FT_Pos*)
489               &decoder->current_subfont->private_dict.family_blues;
490  }
491
492
493  FT_LOCAL_DEF( void )
494  cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
495                           size_t*       count,
496                           FT_Pos*      *data )
497  {
498    FT_ASSERT( decoder && decoder->current_subfont );
499
500    *count = decoder->current_subfont->private_dict.num_family_other_blues;
501    *data  = (FT_Pos*)
502               &decoder->current_subfont->private_dict.family_other_blues;
503  }
504
505
506  FT_LOCAL_DEF( CF2_Int )
507  cf2_getLanguageGroup( CFF_Decoder*  decoder )
508  {
509    FT_ASSERT( decoder && decoder->current_subfont );
510
511    return decoder->current_subfont->private_dict.language_group;
512  }
513
514
515  /* convert unbiased subroutine index to `CF2_Buffer' and */
516  /* return 0 on success                                   */
517  FT_LOCAL_DEF( CF2_Int )
518  cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
519                              CF2_UInt      idx,
520                              CF2_Buffer    buf )
521  {
522    FT_ASSERT( decoder );
523
524    FT_ZERO( buf );
525
526    idx += decoder->globals_bias;
527    if ( idx >= decoder->num_globals )
528      return TRUE;     /* error */
529
530    FT_ASSERT( decoder->globals );
531
532    buf->start =
533    buf->ptr   = decoder->globals[idx];
534    buf->end   = decoder->globals[idx + 1];
535
536    return FALSE;      /* success */
537  }
538
539
540  /* convert AdobeStandardEncoding code to CF2_Buffer; */
541  /* used for seac component                           */
542  FT_LOCAL_DEF( FT_Error )
543  cf2_getSeacComponent( CFF_Decoder*  decoder,
544                        CF2_UInt      code,
545                        CF2_Buffer    buf )
546  {
547    CF2_Int   gid;
548    FT_Byte*  charstring;
549    FT_ULong  len;
550    FT_Error  error;
551
552
553    FT_ASSERT( decoder );
554
555    FT_ZERO( buf );
556
557    gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code );
558    if ( gid < 0 )
559      return FT_THROW( Invalid_Glyph_Format );
560
561    error = cff_get_glyph_data( decoder->builder.face,
562                                gid,
563                                &charstring,
564                                &len );
565    /* TODO: for now, just pass the FreeType error through */
566    if ( error )
567      return error;
568
569    /* assume input has been validated */
570    FT_ASSERT( charstring + len >= charstring );
571
572    buf->start = charstring;
573    buf->end   = charstring + len;
574    buf->ptr   = buf->start;
575
576    return FT_Err_Ok;
577  }
578
579
580  FT_LOCAL_DEF( void )
581  cf2_freeSeacComponent( CFF_Decoder*  decoder,
582                         CF2_Buffer    buf )
583  {
584    FT_ASSERT( decoder );
585
586    cff_free_glyph_data( decoder->builder.face,
587                         (FT_Byte**)&buf->start,
588                         (FT_ULong)( buf->end - buf->start ) );
589  }
590
591
592  FT_LOCAL_DEF( CF2_Int )
593  cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
594                             CF2_UInt      idx,
595                             CF2_Buffer    buf )
596  {
597    FT_ASSERT( decoder );
598
599    FT_ZERO( buf );
600
601    idx += decoder->locals_bias;
602    if ( idx >= decoder->num_locals )
603      return TRUE;     /* error */
604
605    FT_ASSERT( decoder->locals );
606
607    buf->start =
608    buf->ptr   = decoder->locals[idx];
609    buf->end   = decoder->locals[idx + 1];
610
611    return FALSE;      /* success */
612  }
613
614
615  FT_LOCAL_DEF( CF2_Fixed )
616  cf2_getDefaultWidthX( CFF_Decoder*  decoder )
617  {
618    FT_ASSERT( decoder && decoder->current_subfont );
619
620    return cf2_intToFixed(
621             decoder->current_subfont->private_dict.default_width );
622  }
623
624
625  FT_LOCAL_DEF( CF2_Fixed )
626  cf2_getNominalWidthX( CFF_Decoder*  decoder )
627  {
628    FT_ASSERT( decoder && decoder->current_subfont );
629
630    return cf2_intToFixed(
631             decoder->current_subfont->private_dict.nominal_width );
632  }
633
634
635  FT_LOCAL_DEF( void )
636  cf2_outline_reset( CF2_Outline  outline )
637  {
638    CFF_Decoder*  decoder = outline->decoder;
639
640
641    FT_ASSERT( decoder );
642
643    outline->root.windingMomentum = 0;
644
645    FT_GlyphLoader_Rewind( decoder->builder.loader );
646  }
647
648
649  FT_LOCAL_DEF( void )
650  cf2_outline_close( CF2_Outline  outline )
651  {
652    CFF_Decoder*  decoder = outline->decoder;
653
654
655    FT_ASSERT( decoder );
656
657    cff_builder_close_contour( &decoder->builder );
658
659    FT_GlyphLoader_Add( decoder->builder.loader );
660  }
661
662
663/* END */
664