w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ftobjs.c
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * ftobjs.c
4  *
5  * The FreeType private base classes (body).
6  *
7  * Copyright (C) 1996-2020 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT. By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17 
18 
19 #include <freetype/ftlist.h>
20 #include <freetype/ftoutln.h>
21 #include <freetype/ftfntfmt.h>
22 
23 #include <freetype/internal/ftvalid.h>
24 #include <freetype/internal/ftobjs.h>
25 #include <freetype/internal/ftdebug.h>
26 #include <freetype/internal/ftrfork.h>
27 #include <freetype/internal/ftstream.h>
28 #include <freetype/internal/sfnt.h> /* for SFNT_Load_Table_Func */
29 #include <freetype/internal/psaux.h> /* for PS_Driver */
30 
31 #include <freetype/tttables.h>
32 #include <freetype/tttags.h>
33 #include <freetype/ttnameid.h>
34 
35 #include <freetype/internal/services/svprop.h>
36 #include <freetype/internal/services/svsfnt.h>
37 #include <freetype/internal/services/svpostnm.h>
38 #include <freetype/internal/services/svgldict.h>
39 #include <freetype/internal/services/svttcmap.h>
40 #include <freetype/internal/services/svkern.h>
41 #include <freetype/internal/services/svtteng.h>
42 
43 #include <freetype/ftdriver.h>
44 
45 #ifdef FT_CONFIG_OPTION_MAC_FONTS
46 #include "ftbase.h"
47 #endif
48 
49 
50 #ifdef FT_DEBUG_LEVEL_TRACE
51 
52 #include <freetype/ftbitmap.h>
53 
54 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
55  /* We disable the warning `conversion from XXX to YYY, */
56  /* possible loss of data' in order to compile cleanly with */
57  /* the maximum level of warnings: `md5.c' is non-FreeType */
58  /* code, and it gets used during development builds only. */
59 #pragma warning( push )
60 #pragma warning( disable : 4244 )
61 #endif /* _MSC_VER */
62 
63  /* It's easiest to include `md5.c' directly. However, since OpenSSL */
64  /* also provides the same functions, there might be conflicts if */
65  /* both FreeType and OpenSSL are built as static libraries. For */
66  /* this reason, we put the MD5 stuff into the `FT_' namespace. */
67 #define MD5_u32plus FT_MD5_u32plus
68 #define MD5_CTX FT_MD5_CTX
69 #define MD5_Init FT_MD5_Init
70 #define MD5_Update FT_MD5_Update
71 #define MD5_Final FT_MD5_Final
72 
73 #undef HAVE_OPENSSL
74 
75 #include "md5.c"
76 
77 #if defined( _MSC_VER )
78 #pragma warning( pop )
79 #endif
80 
81  static const char* const pixel_modes[] =
82  {
83  "none",
84  "monochrome bitmap",
85  "gray 8-bit bitmap",
86  "gray 2-bit bitmap",
87  "gray 4-bit bitmap",
88  "LCD 8-bit bitmap",
89  "vertical LCD 8-bit bitmap",
90  "BGRA 32-bit color image bitmap"
91  };
92 
93 #endif /* FT_DEBUG_LEVEL_TRACE */
94 
95 
96 #define GRID_FIT_METRICS
97 
98 
99  /* forward declaration */
100  static FT_Error
102  const FT_Open_Args* args,
103  FT_Long face_index,
104  FT_Face *aface,
105  FT_Bool test_mac_fonts );
106 
107 
110  const char* service_id )
111  {
113  FT_ServiceDesc desc = service_descriptors;
114 
115 
116  if ( desc && service_id )
117  {
118  for ( ; desc->serv_id != NULL; desc++ )
119  {
120  if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
121  {
122  result = (FT_Pointer)desc->serv_data;
123  break;
124  }
125  }
126  }
127 
128  return result;
129  }
130 
131 
132  FT_BASE_DEF( void )
134  const FT_Byte* base,
137  {
138  valid->base = base;
139  valid->limit = limit;
140  valid->level = level;
141  valid->error = FT_Err_Ok;
142  }
143 
144 
147  {
148  /* This function doesn't work! None should call it. */
149  FT_UNUSED( valid );
150 
151  return -1;
152  }
153 
154 
155  FT_BASE_DEF( void )
157  FT_Error error )
158  {
159  /* since the cast below also disables the compiler's */
160  /* type check, we introduce a dummy variable, which */
161  /* will be optimized away */
162  volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
163 
164 
165  valid->error = error;
166 
167  /* throw away volatileness; use `jump_buffer' or the */
168  /* compiler may warn about an unused local variable */
169  ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
170  }
171 
172 
173  /*************************************************************************/
174  /*************************************************************************/
175  /*************************************************************************/
176  /**** ****/
177  /**** ****/
178  /**** S T R E A M ****/
179  /**** ****/
180  /**** ****/
181  /*************************************************************************/
182  /*************************************************************************/
183  /*************************************************************************/
184 
185 
186  /* create a new input stream from an FT_Open_Args structure */
187  /* */
191  FT_Stream *astream )
192  {
193  FT_Error error;
194  FT_Memory memory;
196 
197 
198  *astream = NULL;
199 
200  if ( !library )
201  return FT_THROW( Invalid_Library_Handle );
202 
203  if ( !args )
204  return FT_THROW( Invalid_Argument );
205 
206  memory = library->memory;
207 
208  if ( FT_NEW( stream ) )
209  goto Exit;
210 
211  stream->memory = memory;
212 
213  if ( args->flags & FT_OPEN_MEMORY )
214  {
215  /* create a memory-based stream */
217  (const FT_Byte*)args->memory_base,
218  (FT_ULong)args->memory_size );
219  }
220 
221 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
222 
223  else if ( args->flags & FT_OPEN_PATHNAME )
224  {
225  /* create a normal system stream */
226  error = FT_Stream_Open( stream, args->pathname );
227  stream->pathname.pointer = args->pathname;
228  }
229  else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
230  {
231  /* use an existing, user-provided stream */
232 
233  /* in this case, we do not need to allocate a new stream object */
234  /* since the caller is responsible for closing it himself */
235  FT_FREE( stream );
236  stream = args->stream;
237  }
238 
239 #endif
240 
241  else
242  error = FT_THROW( Invalid_Argument );
243 
244  if ( error )
245  FT_FREE( stream );
246  else
247  stream->memory = memory; /* just to be certain */
248 
249  *astream = stream;
250 
251  Exit:
252  return error;
253  }
254 
255 
256  FT_BASE_DEF( void )
258  FT_Int external )
259  {
260  if ( stream )
261  {
262  FT_Memory memory = stream->memory;
263 
264 
266 
267  if ( !external )
268  FT_FREE( stream );
269  }
270  }
271 
272 
273  /**************************************************************************
274  *
275  * The macro FT_COMPONENT is used in trace mode. It is an implicit
276  * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
277  * messages during execution.
278  */
279 #undef FT_COMPONENT
280 #define FT_COMPONENT objs
281 
282 
283  /*************************************************************************/
284  /*************************************************************************/
285  /*************************************************************************/
286  /**** ****/
287  /**** ****/
288  /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
289  /**** ****/
290  /**** ****/
291  /*************************************************************************/
292  /*************************************************************************/
293  /*************************************************************************/
294 
295 
296  static FT_Error
298  {
299  FT_Driver driver = slot->face->driver;
300  FT_Driver_Class clazz = driver->clazz;
301  FT_Memory memory = driver->root.memory;
303  FT_Slot_Internal internal = NULL;
304 
305 
306  slot->library = driver->root.library;
307 
308  if ( FT_NEW( internal ) )
309  goto Exit;
310 
311  slot->internal = internal;
312 
313  if ( FT_DRIVER_USES_OUTLINES( driver ) )
314  error = FT_GlyphLoader_New( memory, &internal->loader );
315 
316  if ( !error && clazz->init_slot )
317  error = clazz->init_slot( slot );
318 
319  Exit:
320  return error;
321  }
322 
323 
324  FT_BASE_DEF( void )
326  {
327  if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
328  {
329  FT_Memory memory = FT_FACE_MEMORY( slot->face );
330 
331 
332  FT_FREE( slot->bitmap.buffer );
333  slot->internal->flags &= ~~FT_GLYPH_OWN_BITMAP;
334  }
335  else
336  {
337  /* assume that the bitmap buffer was stolen or not */
338  /* allocated from the heap */
339  slot->bitmap.buffer = NULL;
340  }
341  }
342 
343 
344  /* overflow-resistant presetting of bitmap position and dimensions; */
345  /* also check whether the size is too large for rendering */
349  const FT_Vector* origin )
350  {
351  FT_Outline* outline = &slot->outline;
352  FT_Bitmap* bitmap = &slot->bitmap;
353 
354  FT_Pixel_Mode pixel_mode;
355 
356  FT_BBox cbox, pbox;
357  FT_Pos x_shift = 0;
358  FT_Pos y_shift = 0;
359  FT_Pos x_left, y_top;
360  FT_Pos width, height, pitch;
361 
362 
363  if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
364  return 1;
365 
366  if ( origin )
367  {
368  x_shift = origin->x;
369  y_shift = origin->y;
370  }
371 
372  /* compute the control box, and grid-fit it, */
373  /* taking into account the origin shift */
374  FT_Outline_Get_CBox( outline, &cbox );
375 
376  /* rough estimate of pixel box */
377  pbox.xMin = ( cbox.xMin >> 6 ) + ( x_shift >> 6 );
378  pbox.yMin = ( cbox.yMin >> 6 ) + ( y_shift >> 6 );
379  pbox.xMax = ( cbox.xMax >> 6 ) + ( x_shift >> 6 );
380  pbox.yMax = ( cbox.yMax >> 6 ) + ( y_shift >> 6 );
381 
382  /* tiny remainder box */
383  cbox.xMin = ( cbox.xMin & 63 ) + ( x_shift & 63 );
384  cbox.yMin = ( cbox.yMin & 63 ) + ( y_shift & 63 );
385  cbox.xMax = ( cbox.xMax & 63 ) + ( x_shift & 63 );
386  cbox.yMax = ( cbox.yMax & 63 ) + ( y_shift & 63 );
387 
388  switch ( mode )
389  {
390  case FT_RENDER_MODE_MONO:
391  pixel_mode = FT_PIXEL_MODE_MONO;
392 #if 1
393  /* x */
394 
395  /* undocumented but confirmed: bbox values get rounded; */
396  /* we do asymmetric rounding so that the center of a pixel */
397  /* gets always included */
398 
399  pbox.xMin += ( cbox.xMin + 31 ) >> 6;
400  pbox.xMax += ( cbox.xMax + 32 ) >> 6;
401 
402  /* if the bbox collapsed, we add a pixel based on the total */
403  /* rounding remainder to cover most of the original cbox */
404 
405  if ( pbox.xMin == pbox.xMax )
406  {
407  if ( ( ( cbox.xMin + 31 ) & 63 ) - 31 +
408  ( ( cbox.xMax + 32 ) & 63 ) - 32 < 0 )
409  pbox.xMin -= 1;
410  else
411  pbox.xMax += 1;
412  }
413 
414  /* y */
415 
416  pbox.yMin += ( cbox.yMin + 31 ) >> 6;
417  pbox.yMax += ( cbox.yMax + 32 ) >> 6;
418 
419  if ( pbox.yMin == pbox.yMax )
420  {
421  if ( ( ( cbox.yMin + 31 ) & 63 ) - 31 +
422  ( ( cbox.yMax + 32 ) & 63 ) - 32 < 0 )
423  pbox.yMin -= 1;
424  else
425  pbox.yMax += 1;
426  }
427 
428  break;
429 #else
430  goto Adjust;
431 #endif
432 
433  case FT_RENDER_MODE_LCD:
434  pixel_mode = FT_PIXEL_MODE_LCD;
435  ft_lcd_padding( &cbox, slot, mode );
436  goto Adjust;
437 
439  pixel_mode = FT_PIXEL_MODE_LCD_V;
440  ft_lcd_padding( &cbox, slot, mode );
441  goto Adjust;
442 
445  default:
446  pixel_mode = FT_PIXEL_MODE_GRAY;
447  Adjust:
448  pbox.xMin += cbox.xMin >> 6;
449  pbox.yMin += cbox.yMin >> 6;
450  pbox.xMax += ( cbox.xMax + 63 ) >> 6;
451  pbox.yMax += ( cbox.yMax + 63 ) >> 6;
452  }
453 
454  x_left = pbox.xMin;
455  y_top = pbox.yMax;
456 
457  width = pbox.xMax - pbox.xMin;
458  height = pbox.yMax - pbox.yMin;
459 
460  switch ( pixel_mode )
461  {
462  case FT_PIXEL_MODE_MONO:
463  pitch = ( ( width + 15 ) >> 4 ) << 1;
464  break;
465 
466  case FT_PIXEL_MODE_LCD:
467  width *= 3;
468  pitch = FT_PAD_CEIL( width, 4 );
469  break;
470 
471  case FT_PIXEL_MODE_LCD_V:
472  height *= 3;
473  /* fall through */
474 
475  case FT_PIXEL_MODE_GRAY:
476  default:
477  pitch = width;
478  }
479 
480  slot->bitmap_left = (FT_Int)x_left;
481  slot->bitmap_top = (FT_Int)y_top;
482 
483  bitmap->pixel_mode = (unsigned char)pixel_mode;
484  bitmap->num_grays = 256;
485  bitmap->width = (unsigned int)width;
486  bitmap->rows = (unsigned int)height;
487  bitmap->pitch = pitch;
488 
489  if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF ||
490  pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF )
491  {
492  FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
493  pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
494  return 1;
495  }
496 
497  return 0;
498  }
499 
500 
501  FT_BASE_DEF( void )
503  FT_Byte* buffer )
504  {
506 
507  slot->bitmap.buffer = buffer;
508 
509  FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
510  }
511 
512 
515  FT_ULong size )
516  {
517  FT_Memory memory = FT_FACE_MEMORY( slot->face );
518  FT_Error error;
519 
520 
521  if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
522  FT_FREE( slot->bitmap.buffer );
523  else
524  slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
525 
526  (void)FT_ALLOC( slot->bitmap.buffer, size );
527  return error;
528  }
529 
530 
531  static void
533  {
534  /* free bitmap if needed */
536 
537  /* clear all public fields in the glyph slot */
538  FT_ZERO( &slot->metrics );
539  FT_ZERO( &slot->outline );
540 
541  slot->bitmap.width = 0;
542  slot->bitmap.rows = 0;
543  slot->bitmap.pitch = 0;
544  slot->bitmap.pixel_mode = 0;
545  /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
546 
547  slot->bitmap_left = 0;
548  slot->bitmap_top = 0;
549  slot->num_subglyphs = 0;
550  slot->subglyphs = NULL;
551  slot->control_data = NULL;
552  slot->control_len = 0;
553  slot->other = NULL;
554  slot->format = FT_GLYPH_FORMAT_NONE;
555 
556  slot->linearHoriAdvance = 0;
557  slot->linearVertAdvance = 0;
558  slot->lsb_delta = 0;
559  slot->rsb_delta = 0;
560  }
561 
562 
563  static void
565  {
566  FT_Driver driver = slot->face->driver;
567  FT_Driver_Class clazz = driver->clazz;
568  FT_Memory memory = driver->root.memory;
569 
570 
571  if ( clazz->done_slot )
572  clazz->done_slot( slot );
573 
574  /* free bitmap buffer if needed */
576 
577  /* slot->internal might be NULL in out-of-memory situations */
578  if ( slot->internal )
579  {
580  /* free glyph loader */
581  if ( FT_DRIVER_USES_OUTLINES( driver ) )
582  {
583  FT_GlyphLoader_Done( slot->internal->loader );
584  slot->internal->loader = NULL;
585  }
586 
587  FT_FREE( slot->internal );
588  }
589  }
590 
591 
592  /* documentation is in ftobjs.h */
593 
596  FT_GlyphSlot *aslot )
597  {
598  FT_Error error;
599  FT_Driver driver;
600  FT_Driver_Class clazz;
601  FT_Memory memory;
603 
604 
605  if ( !face )
606  return FT_THROW( Invalid_Face_Handle );
607 
608  if ( !face->driver )
609  return FT_THROW( Invalid_Argument );
610 
611  driver = face->driver;
612  clazz = driver->clazz;
613  memory = driver->root.memory;
614 
615  FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
616  if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
617  {
618  slot->face = face;
619 
621  if ( error )
622  {
624  FT_FREE( slot );
625  goto Exit;
626  }
627 
628  slot->next = face->glyph;
629  face->glyph = slot;
630 
631  if ( aslot )
632  *aslot = slot;
633  }
634  else if ( aslot )
635  *aslot = NULL;
636 
637 
638  Exit:
639  FT_TRACE4(( "FT_New_GlyphSlot: Return 0x%x\n", error ));
640 
641  return error;
642  }
643 
644 
645  /* documentation is in ftobjs.h */
646 
647  FT_BASE_DEF( void )
649  {
650  if ( slot )
651  {
652  FT_Driver driver = slot->face->driver;
653  FT_Memory memory = driver->root.memory;
656 
657 
658  /* Remove slot from its parent face's list */
659  prev = NULL;
660  cur = slot->face->glyph;
661 
662  while ( cur )
663  {
664  if ( cur == slot )
665  {
666  if ( !prev )
667  slot->face->glyph = cur->next;
668  else
669  prev->next = cur->next;
670 
671  /* finalize client-specific data */
672  if ( slot->generic.finalizer )
673  slot->generic.finalizer( slot );
674 
676  FT_FREE( slot );
677  break;
678  }
679  prev = cur;
680  cur = cur->next;
681  }
682  }
683  }
684 
685 
686  /* documentation is in freetype.h */
687 
688  FT_EXPORT_DEF( void )
690  FT_Matrix* matrix,
691  FT_Vector* delta )
692  {
693  FT_Face_Internal internal;
694 
695 
696  if ( !face )
697  return;
698 
699  internal = face->internal;
700 
701  internal->transform_flags = 0;
702 
703  if ( !matrix )
704  {
705  internal->transform_matrix.xx = 0x10000L;
706  internal->transform_matrix.xy = 0;
707  internal->transform_matrix.yx = 0;
708  internal->transform_matrix.yy = 0x10000L;
709 
710  matrix = &internal->transform_matrix;
711  }
712  else
713  internal->transform_matrix = *matrix;
714 
715  /* set transform_flags bit flag 0 if `matrix' isn't the identity */
716  if ( ( matrix->xy | matrix->yx ) ||
717  matrix->xx != 0x10000L ||
718  matrix->yy != 0x10000L )
719  internal->transform_flags |= 1;
720 
721  if ( !delta )
722  {
723  internal->transform_delta.x = 0;
724  internal->transform_delta.y = 0;
725 
726  delta = &internal->transform_delta;
727  }
728  else
729  internal->transform_delta = *delta;
730 
731  /* set transform_flags bit flag 1 if `delta' isn't the null vector */
732  if ( delta->x | delta->y )
733  internal->transform_flags |= 2;
734  }
735 
736 
737  static FT_Renderer
739 
740 
741 #ifdef GRID_FIT_METRICS
742  static void
744  FT_Bool vertical )
745  {
746  FT_Glyph_Metrics* metrics = &slot->metrics;
748 
749 
750  if ( vertical )
751  {
752  metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
753  metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY );
754 
755  right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingX,
756  metrics->width ) );
757  bottom = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingY,
758  metrics->height ) );
759 
760  metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
761  metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
762 
763  metrics->width = SUB_LONG( right,
764  metrics->vertBearingX );
765  metrics->height = SUB_LONG( bottom,
766  metrics->vertBearingY );
767  }
768  else
769  {
770  metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
771  metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
772 
773  right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->horiBearingX,
774  metrics->width ) );
775  bottom = FT_PIX_FLOOR( SUB_LONG( metrics->horiBearingY,
776  metrics->height ) );
777 
778  metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
779  metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY );
780 
781  metrics->width = SUB_LONG( right,
782  metrics->horiBearingX );
783  metrics->height = SUB_LONG( metrics->horiBearingY,
784  bottom );
785  }
786 
787  metrics->horiAdvance = FT_PIX_ROUND_LONG( metrics->horiAdvance );
788  metrics->vertAdvance = FT_PIX_ROUND_LONG( metrics->vertAdvance );
789  }
790 #endif /* GRID_FIT_METRICS */
791 
792 
793  /* documentation is in freetype.h */
794 
798  FT_Int32 load_flags )
799  {
800  FT_Error error;
801  FT_Driver driver;
804  FT_Bool autohint = FALSE;
805  FT_Module hinter;
806  TT_Face ttface = (TT_Face)face;
807 
808 
809  if ( !face || !face->size || !face->glyph )
810  return FT_THROW( Invalid_Face_Handle );
811 
812  /* The validity test for `glyph_index' is performed by the */
813  /* font drivers. */
814 
815  slot = face->glyph;
817 
818  driver = face->driver;
819  library = driver->root.library;
820  hinter = library->auto_hinter;
821 
822  /* resolve load flags dependencies */
823 
824  if ( load_flags & FT_LOAD_NO_RECURSE )
825  load_flags |= FT_LOAD_NO_SCALE |
827 
828  if ( load_flags & FT_LOAD_NO_SCALE )
829  {
830  load_flags |= FT_LOAD_NO_HINTING |
832 
833  load_flags &= ~~FT_LOAD_RENDER;
834  }
835 
836  if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
837  load_flags &= ~~FT_LOAD_RENDER;
838 
839  /*
840  * Determine whether we need to auto-hint or not.
841  * The general rules are:
842  *
843  * - Do only auto-hinting if we have
844  *
845  * - a hinter module,
846  * - a scalable font,
847  * - not a tricky font, and
848  * - no transforms except simple slants and/or rotations by
849  * integer multiples of 90 degrees.
850  *
851  * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
852  * have a native font hinter.
853  *
854  * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
855  * any hinting bytecode in the TrueType/OpenType font.
856  *
857  * - Exception: The font is `tricky' and requires the native hinter to
858  * load properly.
859  */
860 
861  if ( hinter &&
862  !( load_flags & FT_LOAD_NO_HINTING ) &&
863  !( load_flags & FT_LOAD_NO_AUTOHINT ) &&
864  FT_IS_SCALABLE( face ) &&
865  !FT_IS_TRICKY( face ) &&
866  ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) ||
867  ( face->internal->transform_matrix.yx == 0 &&
868  face->internal->transform_matrix.xx != 0 ) ||
869  ( face->internal->transform_matrix.xx == 0 &&
870  face->internal->transform_matrix.yx != 0 ) ) )
871  {
872  if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
873  !FT_DRIVER_HAS_HINTER( driver ) )
874  autohint = TRUE;
875  else
876  {
877  FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
878  FT_Bool is_light_type1;
879 
880 
881  /* only the new Adobe engine (for both CFF and Type 1) is `light'; */
882  /* we use `strstr' to catch both `Type 1' and `CID Type 1' */
883  is_light_type1 =
884  ft_strstr( FT_Get_Font_Format( face ), "Type 1" ) != NULL &&
885  ((PS_Driver)driver)->hinting_engine == FT_HINTING_ADOBE;
886 
887  /* the check for `num_locations' assures that we actually */
888  /* test for instructions in a TTF and not in a CFF-based OTF */
889  /* */
890  /* since `maxSizeOfInstructions' might be unreliable, we */
891  /* check the size of the `fpgm' and `prep' tables, too -- */
892  /* the assumption is that there don't exist real TTFs where */
893  /* both `fpgm' and `prep' tables are missing */
894  if ( ( mode == FT_RENDER_MODE_LIGHT &&
895  ( !FT_DRIVER_HINTS_LIGHTLY( driver ) &&
896  !is_light_type1 ) ) ||
897  ( FT_IS_SFNT( face ) &&
898  ttface->num_locations &&
899  ttface->max_profile.maxSizeOfInstructions == 0 &&
900  ttface->font_program_size == 0 &&
901  ttface->cvt_program_size == 0 ) )
902  autohint = TRUE;
903  }
904  }
905 
906  if ( autohint )
907  {
908  FT_AutoHinter_Interface hinting;
909 
910 
911  /* try to load embedded bitmaps first if available */
912  /* */
913  /* XXX: This is really a temporary hack that should disappear */
914  /* promptly with FreeType 2.1! */
915  /* */
916  if ( FT_HAS_FIXED_SIZES( face ) &&
917  ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
918  {
919  error = driver->clazz->load_glyph( slot, face->size,
920  glyph_index,
921  load_flags | FT_LOAD_SBITS_ONLY );
922 
923  if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
924  goto Load_Ok;
925  }
926 
927  {
928  FT_Face_Internal internal = face->internal;
929  FT_Int transform_flags = internal->transform_flags;
930 
931 
932  /* since the auto-hinter calls FT_Load_Glyph by itself, */
933  /* make sure that glyphs aren't transformed */
934  internal->transform_flags = 0;
935 
936  /* load auto-hinted outline */
937  hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface;
938 
939  error = hinting->load_glyph( (FT_AutoHinter)hinter,
940  slot, face->size,
941  glyph_index, load_flags );
942 
943  internal->transform_flags = transform_flags;
944  }
945  }
946  else
947  {
948  error = driver->clazz->load_glyph( slot,
949  face->size,
950  glyph_index,
951  load_flags );
952  if ( error )
953  goto Exit;
954 
955  if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
956  {
957  /* check that the loaded outline is correct */
958  error = FT_Outline_Check( &slot->outline );
959  if ( error )
960  goto Exit;
961 
962 #ifdef GRID_FIT_METRICS
963  if ( !( load_flags & FT_LOAD_NO_HINTING ) )
965  slot,
966  FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
967 #endif
968  }
969  }
970 
971  Load_Ok:
972  /* compute the advance */
973  if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
974  {
975  slot->advance.x = 0;
976  slot->advance.y = slot->metrics.vertAdvance;
977  }
978  else
979  {
980  slot->advance.x = slot->metrics.horiAdvance;
981  slot->advance.y = 0;
982  }
983 
984  /* compute the linear advance in 16.16 pixels */
985  if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
986  FT_IS_SCALABLE( face ) )
987  {
989 
990 
991  /* it's tricky! */
992  slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
993  metrics->x_scale, 64 );
994 
995  slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
996  metrics->y_scale, 64 );
997  }
998 
999  if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
1000  {
1001  FT_Face_Internal internal = face->internal;
1002 
1003 
1004  /* now, transform the glyph image if needed */
1005  if ( internal->transform_flags )
1006  {
1007  /* get renderer */
1009 
1010 
1011  if ( renderer )
1012  error = renderer->clazz->transform_glyph(
1013  renderer, slot,
1014  &internal->transform_matrix,
1015  &internal->transform_delta );
1016  else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
1017  {
1018  /* apply `standard' transformation if no renderer is available */
1019  if ( internal->transform_flags & 1 )
1020  FT_Outline_Transform( &slot->outline,
1021  &internal->transform_matrix );
1022 
1023  if ( internal->transform_flags & 2 )
1024  FT_Outline_Translate( &slot->outline,
1025  internal->transform_delta.x,
1026  internal->transform_delta.y );
1027  }
1028 
1029  /* transform advance */
1030  FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
1031  }
1032  }
1033 
1034  slot->glyph_index = glyph_index;
1035  slot->internal->load_flags = load_flags;
1036 
1037  /* do we need to render the image or preset the bitmap now? */
1038  if ( !error &&
1039  ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
1040  slot->format != FT_GLYPH_FORMAT_BITMAP &&
1041  slot->format != FT_GLYPH_FORMAT_COMPOSITE )
1042  {
1043  FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
1044 
1045 
1046  if ( mode == FT_RENDER_MODE_NORMAL &&
1047  load_flags & FT_LOAD_MONOCHROME )
1049 
1050  if ( load_flags & FT_LOAD_RENDER )
1052  else
1054  }
1055 
1056 #ifdef FT_DEBUG_LEVEL_TRACE
1057  FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n",
1058  glyph_index, load_flags ));
1059  FT_TRACE5(( " x advance: %f\n", slot->advance.x / 64.0 ));
1060  FT_TRACE5(( " y advance: %f\n", slot->advance.y / 64.0 ));
1061  FT_TRACE5(( " linear x advance: %f\n",
1062  slot->linearHoriAdvance / 65536.0 ));
1063  FT_TRACE5(( " linear y advance: %f\n",
1064  slot->linearVertAdvance / 65536.0 ));
1065  FT_TRACE5(( "\n" ));
1066  FT_TRACE5(( " bitmap %dx%d, %s (mode %d)\n",
1067  slot->bitmap.width,
1068  slot->bitmap.rows,
1069  pixel_modes[slot->bitmap.pixel_mode],
1070  slot->bitmap.pixel_mode ));
1071  FT_TRACE5(( "\n" ));
1072 
1073  {
1074  FT_Glyph_Metrics* metrics = &slot->metrics;
1075 
1076 
1077  FT_TRACE5(( " metrics:\n" ));
1078  FT_TRACE5(( " width: %f\n", metrics->width / 64.0 ));
1079  FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
1080  FT_TRACE5(( "\n" ));
1081  FT_TRACE5(( " horiBearingX: %f\n", metrics->horiBearingX / 64.0 ));
1082  FT_TRACE5(( " horiBearingY: %f\n", metrics->horiBearingY / 64.0 ));
1083  FT_TRACE5(( " horiAdvance: %f\n", metrics->horiAdvance / 64.0 ));
1084  FT_TRACE5(( "\n" ));
1085  FT_TRACE5(( " vertBearingX: %f\n", metrics->vertBearingX / 64.0 ));
1086  FT_TRACE5(( " vertBearingY: %f\n", metrics->vertBearingY / 64.0 ));
1087  FT_TRACE5(( " vertAdvance: %f\n", metrics->vertAdvance / 64.0 ));
1088  }
1089 #endif
1090 
1091  Exit:
1092  return error;
1093  }
1094 
1095 
1096  /* documentation is in freetype.h */
1097 
1101  FT_Int32 load_flags )
1102  {
1104 
1105 
1106  if ( !face )
1107  return FT_THROW( Invalid_Face_Handle );
1108 
1110  if ( face->charmap )
1112 
1113  return FT_Load_Glyph( face, glyph_index, load_flags );
1114  }
1115 
1116 
1117  /* destructor for sizes list */
1118  static void
1120  FT_Size size,
1121  FT_Driver driver )
1122  {
1123  /* finalize client-specific data */
1124  if ( size->generic.finalizer )
1125  size->generic.finalizer( size );
1126 
1127  /* finalize format-specific stuff */
1128  if ( driver->clazz->done_size )
1129  driver->clazz->done_size( size );
1130 
1131  FT_FREE( size->internal );
1132  FT_FREE( size );
1133  }
1134 
1135 
1136  static void
1138 
1139 
1140  static void
1142  FT_Memory memory )
1143  {
1144  FT_Int n;
1145 
1146 
1147  if ( !face )
1148  return;
1149 
1150  for ( n = 0; n < face->num_charmaps; n++ )
1151  {
1152  FT_CMap cmap = FT_CMAP( face->charmaps[n] );
1153 
1154 
1156 
1157  face->charmaps[n] = NULL;
1158  }
1159 
1160  FT_FREE( face->charmaps );
1161  face->num_charmaps = 0;
1162  }
1163 
1164 
1165  /* destructor for faces list */
1166  static void
1168  FT_Face face,
1169  FT_Driver driver )
1170  {
1171  FT_Driver_Class clazz = driver->clazz;
1172 
1173 
1174  /* discard auto-hinting data */
1175  if ( face->autohint.finalizer )
1177 
1178  /* Discard glyph slots for this face. */
1179  /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
1180  while ( face->glyph )
1182 
1183  /* discard all sizes for this face */
1186  memory,
1187  driver );
1188  face->size = NULL;
1189 
1190  /* now discard client data */
1191  if ( face->generic.finalizer )
1192  face->generic.finalizer( face );
1193 
1194  /* discard charmaps */
1195  destroy_charmaps( face, memory );
1196 
1197  /* finalize format-specific stuff */
1198  if ( clazz->done_face )
1199  clazz->done_face( face );
1200 
1201  /* close the stream for this face if needed */
1203  face->stream,
1205 
1206  face->stream = NULL;
1207 
1208  /* get rid of it */
1209  if ( face->internal )
1210  {
1211  FT_FREE( face->internal );
1212  }
1213  FT_FREE( face );
1214  }
1215 
1216 
1217  static void
1219  {
1220  FT_List_Finalize( &driver->faces_list,
1222  driver->root.memory,
1223  driver );
1224  }
1225 
1226 
1227  /**************************************************************************
1228  *
1229  * @Function:
1230  * find_unicode_charmap
1231  *
1232  * @Description:
1233  * This function finds a Unicode charmap, if there is one.
1234  * And if there is more than one, it tries to favour the more
1235  * extensive one, i.e., one that supports UCS-4 against those which
1236  * are limited to the BMP (said UCS-2 encoding.)
1237  *
1238  * This function is called from open_face() (just below), and also
1239  * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).
1240  */
1241  static FT_Error
1243  {
1244  FT_CharMap* first;
1245  FT_CharMap* cur;
1246 
1247 
1248  /* caller should have already checked that `face' is valid */
1249  FT_ASSERT( face );
1250 
1251  first = face->charmaps;
1252 
1253  if ( !first )
1254  return FT_THROW( Invalid_CharMap_Handle );
1255 
1256  /*
1257  * The original TrueType specification(s) only specified charmap
1258  * formats that are capable of mapping 8 or 16 bit character codes to
1259  * glyph indices.
1260  *
1261  * However, recent updates to the Apple and OpenType specifications
1262  * introduced new formats that are capable of mapping 32-bit character
1263  * codes as well. And these are already used on some fonts, mainly to
1264  * map non-BMP Asian ideographs as defined in Unicode.
1265  *
1266  * For compatibility purposes, these fonts generally come with
1267  * *several* Unicode charmaps:
1268  *
1269  * - One of them in the "old" 16-bit format, that cannot access
1270  * all glyphs in the font.
1271  *
1272  * - Another one in the "new" 32-bit format, that can access all
1273  * the glyphs.
1274  *
1275  * This function has been written to always favor a 32-bit charmap
1276  * when found. Otherwise, a 16-bit one is returned when found.
1277  */
1278 
1279  /* Since the `interesting' table, with IDs (3,10), is normally the */
1280  /* last one, we loop backwards. This loses with type1 fonts with */
1281  /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
1282  /* chars (.01% ?), and this is the same about 99.99% of the time! */
1283 
1284  cur = first + face->num_charmaps; /* points after the last one */
1285 
1286  for ( ; --cur >= first; )
1287  {
1288  if ( cur[0]->encoding == FT_ENCODING_UNICODE )
1289  {
1290  /* XXX If some new encodings to represent UCS-4 are added, */
1291  /* they should be added here. */
1292  if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
1293  cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
1294  ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
1295  cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
1296  {
1297  face->charmap = cur[0];
1298  return FT_Err_Ok;
1299  }
1300  }
1301  }
1302 
1303  /* We do not have any UCS-4 charmap. */
1304  /* Do the loop again and search for UCS-2 charmaps. */
1305  cur = first + face->num_charmaps;
1306 
1307  for ( ; --cur >= first; )
1308  {
1309  if ( cur[0]->encoding == FT_ENCODING_UNICODE )
1310  {
1311  face->charmap = cur[0];
1312  return FT_Err_Ok;
1313  }
1314  }
1315 
1316  return FT_THROW( Invalid_CharMap_Handle );
1317  }
1318 
1319 
1320  /**************************************************************************
1321  *
1322  * @Function:
1323  * find_variant_selector_charmap
1324  *
1325  * @Description:
1326  * This function finds the variant selector charmap, if there is one.
1327  * There can only be one (platform=0, specific=5, format=14).
1328  */
1329  static FT_CharMap
1331  {
1332  FT_CharMap* first;
1333  FT_CharMap* end;
1334  FT_CharMap* cur;
1335 
1336 
1337  /* caller should have already checked that `face' is valid */
1338  FT_ASSERT( face );
1339 
1340  first = face->charmaps;
1341 
1342  if ( !first )
1343  return NULL;
1344 
1345  end = first + face->num_charmaps; /* points after the last one */
1346 
1347  for ( cur = first; cur < end; cur++ )
1348  {
1349  if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
1350  cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
1351  FT_Get_CMap_Format( cur[0] ) == 14 )
1352  return cur[0];
1353  }
1354 
1355  return NULL;
1356  }
1357 
1358 
1359  /**************************************************************************
1360  *
1361  * @Function:
1362  * open_face
1363  *
1364  * @Description:
1365  * This function does some work for FT_Open_Face().
1366  */
1367  static FT_Error
1369  FT_Stream *astream,
1370  FT_Bool external_stream,
1371  FT_Long face_index,
1372  FT_Int num_params,
1374  FT_Face *aface )
1375  {
1376  FT_Memory memory;
1377  FT_Driver_Class clazz;
1378  FT_Face face = NULL;
1379  FT_Face_Internal internal = NULL;
1380 
1381  FT_Error error, error2;
1382 
1383 
1384  clazz = driver->clazz;
1385  memory = driver->root.memory;
1386 
1387  /* allocate the face object and perform basic initialization */
1388  if ( FT_ALLOC( face, clazz->face_object_size ) )
1389  goto Fail;
1390 
1391  face->driver = driver;
1392  face->memory = memory;
1393  face->stream = *astream;
1394 
1395  /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
1396  if ( external_stream )
1398 
1399  if ( FT_NEW( internal ) )
1400  goto Fail;
1401 
1402  face->internal = internal;
1403 
1404 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1405  {
1406  int i;
1407 
1408 
1409  face->internal->incremental_interface = NULL;
1410  for ( i = 0; i < num_params && !face->internal->incremental_interface;
1411  i++ )
1413  face->internal->incremental_interface =
1415  }
1416 #endif
1417 
1418  face->internal->random_seed = -1;
1419 
1420  if ( clazz->init_face )
1421  error = clazz->init_face( *astream,
1422  face,
1423  (FT_Int)face_index,
1424  num_params,
1425  params );
1426  *astream = face->stream; /* Stream may have been changed. */
1427  if ( error )
1428  goto Fail;
1429 
1430  /* select Unicode charmap by default */
1431  error2 = find_unicode_charmap( face );
1432 
1433  /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1434  /* is returned. */
1435 
1436  /* no error should happen, but we want to play safe */
1437  if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) )
1438  {
1439  error = error2;
1440  goto Fail;
1441  }
1442 
1443  *aface = face;
1444 
1445  Fail:
1446  if ( error )
1447  {
1448  destroy_charmaps( face, memory );
1449  if ( clazz->done_face )
1450  clazz->done_face( face );
1451  FT_FREE( internal );
1452  FT_FREE( face );
1453  *aface = NULL;
1454  }
1455 
1456  return error;
1457  }
1458 
1459 
1460  /* there's a Mac-specific extended implementation of FT_New_Face() */
1461  /* in src/base/ftmac.c */
1462 
1463 #ifndef FT_MACINTOSH
1464 
1465  /* documentation is in freetype.h */
1466 
1469  const char* pathname,
1470  FT_Long face_index,
1471  FT_Face *aface )
1472  {
1474 
1475 
1476  /* test for valid `library' and `aface' delayed to `FT_Open_Face' */
1477  if ( !pathname )
1478  return FT_THROW( Invalid_Argument );
1479 
1480  args.flags = FT_OPEN_PATHNAME;
1481  args.pathname = (char*)pathname;
1482  args.stream = NULL;
1483 
1484  return ft_open_face_internal( library, &args, face_index, aface, 1 );
1485  }
1486 
1487 #endif
1488 
1489 
1490  /* documentation is in freetype.h */
1491 
1494  const FT_Byte* file_base,
1496  FT_Long face_index,
1497  FT_Face *aface )
1498  {
1500 
1501 
1502  /* test for valid `library' and `face' delayed to `FT_Open_Face' */
1503  if ( !file_base )
1504  return FT_THROW( Invalid_Argument );
1505 
1506  args.flags = FT_OPEN_MEMORY;
1507  args.memory_base = file_base;
1508  args.memory_size = file_size;
1509  args.stream = NULL;
1510 
1511  return ft_open_face_internal( library, &args, face_index, aface, 1 );
1512  }
1513 
1514 
1515 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1516 
1517  /* The behavior here is very similar to that in base/ftmac.c, but it */
1518  /* is designed to work on non-mac systems, so no mac specific calls. */
1519  /* */
1520  /* We look at the file and determine if it is a mac dfont file or a mac */
1521  /* resource file, or a macbinary file containing a mac resource file. */
1522  /* */
1523  /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1524  /* the point, especially since there may be multiple `FOND' resources. */
1525  /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1526  /* they occur in the file. */
1527  /* */
1528  /* Note that multiple `POST' resources do not mean multiple postscript */
1529  /* fonts; they all get jammed together to make what is essentially a */
1530  /* pfb file. */
1531  /* */
1532  /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1533  /* */
1534  /* As soon as we get an `sfnt' load it into memory and pass it off to */
1535  /* FT_Open_Face. */
1536  /* */
1537  /* If we have a (set of) `POST' resources, massage them into a (memory) */
1538  /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1539  /* going to try to save the kerning info. After all that lives in the */
1540  /* `FOND' which isn't in the file containing the `POST' resources so */
1541  /* we don't really have access to it. */
1542 
1543 
1544  /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1545  /* It frees the memory it uses. */
1546  /* From `ftmac.c'. */
1547  static void
1548  memory_stream_close( FT_Stream stream )
1549  {
1550  FT_Memory memory = stream->memory;
1551 
1552 
1553  FT_FREE( stream->base );
1554 
1555  stream->size = 0;
1556  stream->base = NULL;
1557  stream->close = NULL;
1558  }
1559 
1560 
1561  /* Create a new memory stream from a buffer and a size. */
1562  /* From `ftmac.c'. */
1563  static FT_Error
1564  new_memory_stream( FT_Library library,
1565  FT_Byte* base,
1566  FT_ULong size,
1568  FT_Stream *astream )
1569  {
1570  FT_Error error;
1571  FT_Memory memory;
1572  FT_Stream stream = NULL;
1573 
1574 
1575  if ( !library )
1576  return FT_THROW( Invalid_Library_Handle );
1577 
1578  if ( !base )
1579  return FT_THROW( Invalid_Argument );
1580 
1581  *astream = NULL;
1582  memory = library->memory;
1583  if ( FT_NEW( stream ) )
1584  goto Exit;
1585 
1587 
1588  stream->close = close;
1589 
1590  *astream = stream;
1591 
1592  Exit:
1593  return error;
1594  }
1595 
1596 
1597  /* Create a new FT_Face given a buffer and a driver name. */
1598  /* From `ftmac.c'. */
1600  open_face_from_buffer( FT_Library library,
1601  FT_Byte* base,
1602  FT_ULong size,
1603  FT_Long face_index,
1604  const char* driver_name,
1605  FT_Face *aface )
1606  {
1608  FT_Error error;
1609  FT_Stream stream = NULL;
1610  FT_Memory memory = library->memory;
1611 
1612 
1613  error = new_memory_stream( library,
1614  base,
1615  size,
1616  memory_stream_close,
1617  &stream );
1618  if ( error )
1619  {
1620  FT_FREE( base );
1621  return error;
1622  }
1623 
1624  args.flags = FT_OPEN_STREAM;
1625  args.stream = stream;
1626  if ( driver_name )
1627  {
1628  args.flags = args.flags | FT_OPEN_DRIVER;
1629  args.driver = FT_Get_Module( library, driver_name );
1630  }
1631 
1632 #ifdef FT_MACINTOSH
1633  /* At this point, the face index has served its purpose; */
1634  /* whoever calls this function has already used it to */
1635  /* locate the correct font data. We should not propagate */
1636  /* this index to FT_Open_Face() (unless it is negative). */
1637 
1638  if ( face_index > 0 )
1639  face_index &= 0x7FFF0000L; /* retain GX data */
1640 #endif
1641 
1642  error = ft_open_face_internal( library, &args, face_index, aface, 0 );
1643 
1644  if ( !error )
1645  (*aface)->face_flags &= ~~FT_FACE_FLAG_EXTERNAL_STREAM;
1646  else
1647 #ifdef FT_MACINTOSH
1648  FT_Stream_Free( stream, 0 );
1649 #else
1650  {
1652  FT_FREE( stream );
1653  }
1654 #endif
1655 
1656  return error;
1657  }
1658 
1659 
1660  /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1661  /* `offset' and `length' must exclude the binary header in tables. */
1662 
1663  /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1664  /* format too. Here, since we can't expect that the TrueType font */
1665  /* driver is loaded unconditionally, we must parse the font by */
1666  /* ourselves. We are only interested in the name of the table and */
1667  /* the offset. */
1668 
1669  static FT_Error
1670  ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
1671  FT_Long face_index,
1672  FT_ULong* offset,
1673  FT_ULong* length,
1674  FT_Bool* is_sfnt_cid )
1675  {
1676  FT_Error error;
1677  FT_UShort numTables;
1678  FT_Long pstable_index;
1679  FT_ULong tag;
1680  int i;
1681 
1682 
1683  *offset = 0;
1684  *length = 0;
1685  *is_sfnt_cid = FALSE;
1686 
1687  /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1688 
1689  /* version check for 'typ1' (should be ignored?) */
1690  if ( FT_READ_ULONG( tag ) )
1691  return error;
1692  if ( tag != TTAG_typ1 )
1693  return FT_THROW( Unknown_File_Format );
1694 
1695  if ( FT_READ_USHORT( numTables ) )
1696  return error;
1697  if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1698  return error;
1699 
1700  pstable_index = -1;
1701  *is_sfnt_cid = FALSE;
1702 
1703  for ( i = 0; i < numTables; i++ )
1704  {
1705  if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
1707  return error;
1708 
1709  if ( tag == TTAG_CID )
1710  {
1711  pstable_index++;
1712  *offset += 22;
1713  *length -= 22;
1714  *is_sfnt_cid = TRUE;
1715  if ( face_index < 0 )
1716  return FT_Err_Ok;
1717  }
1718  else if ( tag == TTAG_TYP1 )
1719  {
1720  pstable_index++;
1721  *offset += 24;
1722  *length -= 24;
1723  *is_sfnt_cid = FALSE;
1724  if ( face_index < 0 )
1725  return FT_Err_Ok;
1726  }
1727  if ( face_index >= 0 && pstable_index == face_index )
1728  return FT_Err_Ok;
1729  }
1730 
1731  return FT_THROW( Table_Missing );
1732  }
1733 
1734 
1736  open_face_PS_from_sfnt_stream( FT_Library library,
1737  FT_Stream stream,
1738  FT_Long face_index,
1739  FT_Int num_params,
1741  FT_Face *aface )
1742  {
1743  FT_Error error;
1744  FT_Memory memory = library->memory;
1746  FT_ULong pos;
1747  FT_Bool is_sfnt_cid;
1748  FT_Byte* sfnt_ps = NULL;
1749 
1750  FT_UNUSED( num_params );
1751  FT_UNUSED( params );
1752 
1753 
1754  /* ignore GX stuff */
1755  if ( face_index > 0 )
1756  face_index &= 0xFFFFL;
1757 
1758  pos = FT_STREAM_POS();
1759 
1760  error = ft_lookup_PS_in_sfnt_stream( stream,
1761  face_index,
1762  &offset,
1763  &length,
1764  &is_sfnt_cid );
1765  if ( error )
1766  goto Exit;
1767 
1768  if ( offset > stream->size )
1769  {
1770  FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" ));
1771  error = FT_THROW( Invalid_Table );
1772  goto Exit;
1773  }
1774  else if ( length > stream->size - offset )
1775  {
1776  FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" ));
1777  error = FT_THROW( Invalid_Table );
1778  goto Exit;
1779  }
1780 
1782  if ( error )
1783  goto Exit;
1784 
1785  if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
1786  goto Exit;
1787 
1788  error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
1789  if ( error )
1790  {
1791  FT_FREE( sfnt_ps );
1792  goto Exit;
1793  }
1794 
1795  error = open_face_from_buffer( library,
1796  sfnt_ps,
1797  length,
1798  FT_MIN( face_index, 0 ),
1799  is_sfnt_cid ? "cid" : "type1",
1800  aface );
1801  Exit:
1802  {
1803  FT_Error error1;
1804 
1805 
1806  if ( FT_ERR_EQ( error, Unknown_File_Format ) )
1807  {
1808  error1 = FT_Stream_Seek( stream, pos );
1809  if ( error1 )
1810  return error1;
1811  }
1812 
1813  return error;
1814  }
1815  }
1816 
1817 
1818 #ifndef FT_MACINTOSH
1819 
1820  /* The resource header says we've got resource_cnt `POST' (type1) */
1821  /* resources in this file. They all need to be coalesced into */
1822  /* one lump which gets passed on to the type1 driver. */
1823  /* Here can be only one PostScript font in a file so face_index */
1824  /* must be 0 (or -1). */
1825  /* */
1826  static FT_Error
1827  Mac_Read_POST_Resource( FT_Library library,
1828  FT_Stream stream,
1829  FT_Long *offsets,
1830  FT_Long resource_cnt,
1831  FT_Long face_index,
1832  FT_Face *aface )
1833  {
1834  FT_Error error = FT_ERR( Cannot_Open_Resource );
1835  FT_Memory memory = library->memory;
1836 
1837  FT_Byte* pfb_data = NULL;
1838  int i, type, flags;
1839  FT_ULong len;
1840  FT_ULong pfb_len, pfb_pos, pfb_lenpos;
1841  FT_ULong rlen, temp;
1842 
1843 
1844  if ( face_index == -1 )
1845  face_index = 0;
1846  if ( face_index != 0 )
1847  return error;
1848 
1849  /* Find the length of all the POST resources, concatenated. Assume */
1850  /* worst case (each resource in its own section). */
1851  pfb_len = 0;
1852  for ( i = 0; i < resource_cnt; i++ )
1853  {
1854  error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] );
1855  if ( error )
1856  goto Exit;
1857  if ( FT_READ_ULONG( temp ) ) /* actually LONG */
1858  goto Exit;
1859 
1860  /* FT2 allocator takes signed long buffer length,
1861  * too large value causing overflow should be checked
1862  */
1863  FT_TRACE4(( " POST fragment #%d: length=0x%08lx"
1864  " total pfb_len=0x%08lx\n",
1865  i, temp, pfb_len + temp + 6 ));
1866 
1867  if ( FT_MAC_RFORK_MAX_LEN < temp ||
1868  FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 )
1869  {
1870  FT_TRACE2(( " MacOS resource length cannot exceed"
1871  " 0x%08lx\n",
1872  FT_MAC_RFORK_MAX_LEN ));
1873 
1874  error = FT_THROW( Invalid_Offset );
1875  goto Exit;
1876  }
1877 
1878  pfb_len += temp + 6;
1879  }
1880 
1881  FT_TRACE2(( " total buffer size to concatenate"
1882  " %ld POST fragments: 0x%08lx\n",
1883  resource_cnt, pfb_len + 2 ));
1884 
1885  if ( pfb_len + 2 < 6 )
1886  {
1887  FT_TRACE2(( " too long fragment length makes"
1888  " pfb_len confused: pfb_len=0x%08lx\n",
1889  pfb_len ));
1890 
1891  error = FT_THROW( Array_Too_Large );
1892  goto Exit;
1893  }
1894 
1895  if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
1896  goto Exit;
1897 
1898  pfb_data[0] = 0x80;
1899  pfb_data[1] = 1; /* Ascii section */
1900  pfb_data[2] = 0; /* 4-byte length, fill in later */
1901  pfb_data[3] = 0;
1902  pfb_data[4] = 0;
1903  pfb_data[5] = 0;
1904  pfb_pos = 6;
1905  pfb_lenpos = 2;
1906 
1907  len = 0;
1908  type = 1;
1909 
1910  for ( i = 0; i < resource_cnt; i++ )
1911  {
1912  error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] );
1913  if ( error )
1914  goto Exit2;
1915  if ( FT_READ_ULONG( rlen ) )
1916  goto Exit2;
1917 
1918  /* FT2 allocator takes signed long buffer length,
1919  * too large fragment length causing overflow should be checked
1920  */
1921  if ( 0x7FFFFFFFUL < rlen )
1922  {
1923  error = FT_THROW( Invalid_Offset );
1924  goto Exit2;
1925  }
1926 
1927  if ( FT_READ_USHORT( flags ) )
1928  goto Exit2;
1929 
1930  FT_TRACE3(( "POST fragment[%d]:"
1931  " offsets=0x%08lx, rlen=0x%08lx, flags=0x%04x\n",
1932  i, offsets[i], rlen, flags ));
1933 
1934  error = FT_ERR( Array_Too_Large );
1935 
1936  /* postpone the check of `rlen longer than buffer' */
1937  /* until `FT_Stream_Read' */
1938 
1939  if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */
1940  {
1941  FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n",
1942  i ));
1943  continue;
1944  }
1945 
1946  /* the flags are part of the resource, so rlen >= 2, */
1947  /* but some fonts declare rlen = 0 for empty fragment */
1948  if ( rlen > 2 )
1949  rlen -= 2;
1950  else
1951  rlen = 0;
1952 
1953  if ( ( flags >> 8 ) == type )
1954  len += rlen;
1955  else
1956  {
1957  FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer"
1958  " %p + 0x%08lx\n",
1959  i, pfb_data, pfb_lenpos ));
1960 
1961  if ( pfb_lenpos + 3 > pfb_len + 2 )
1962  goto Exit2;
1963 
1964  pfb_data[pfb_lenpos ] = (FT_Byte)( len );
1965  pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
1966  pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
1967  pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
1968 
1969  if ( ( flags >> 8 ) == 5 ) /* End of font mark */
1970  break;
1971 
1972  FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer"
1973  " %p + 0x%08lx\n",
1974  i, pfb_data, pfb_pos ));
1975 
1976  if ( pfb_pos + 6 > pfb_len + 2 )
1977  goto Exit2;
1978 
1979  pfb_data[pfb_pos++] = 0x80;
1980 
1981  type = flags >> 8;
1982  len = rlen;
1983 
1984  pfb_data[pfb_pos++] = (FT_Byte)type;
1985  pfb_lenpos = pfb_pos;
1986  pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */
1987  pfb_data[pfb_pos++] = 0;
1988  pfb_data[pfb_pos++] = 0;
1989  pfb_data[pfb_pos++] = 0;
1990  }
1991 
1992  if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
1993  goto Exit2;
1994 
1995  FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer"
1996  " %p + 0x%08lx\n",
1997  i, rlen, pfb_data, pfb_pos ));
1998 
1999  error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
2000  if ( error )
2001  goto Exit2;
2002 
2003  pfb_pos += rlen;
2004  }
2005 
2006  error = FT_ERR( Array_Too_Large );
2007 
2008  if ( pfb_pos + 2 > pfb_len + 2 )
2009  goto Exit2;
2010  pfb_data[pfb_pos++] = 0x80;
2011  pfb_data[pfb_pos++] = 3;
2012 
2013  if ( pfb_lenpos + 3 > pfb_len + 2 )
2014  goto Exit2;
2015  pfb_data[pfb_lenpos ] = (FT_Byte)( len );
2016  pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
2017  pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
2018  pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
2019 
2020  return open_face_from_buffer( library,
2021  pfb_data,
2022  pfb_pos,
2023  face_index,
2024  "type1",
2025  aface );
2026 
2027  Exit2:
2028  if ( FT_ERR_EQ( error, Array_Too_Large ) )
2029  FT_TRACE2(( " Abort due to too-short buffer to store"
2030  " all POST fragments\n" ));
2031  else if ( FT_ERR_EQ( error, Invalid_Offset ) )
2032  FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" ));
2033 
2034  if ( error )
2035  error = FT_ERR( Cannot_Open_Resource );
2036  FT_FREE( pfb_data );
2037 
2038  Exit:
2039  return error;
2040  }
2041 
2042 
2043  /* The resource header says we've got resource_cnt `sfnt' */
2044  /* (TrueType/OpenType) resources in this file. Look through */
2045  /* them for the one indicated by face_index, load it into mem, */
2046  /* pass it on to the truetype driver, and return it. */
2047  /* */
2048  static FT_Error
2049  Mac_Read_sfnt_Resource( FT_Library library,
2050  FT_Stream stream,
2051  FT_Long *offsets,
2052  FT_Long resource_cnt,
2053  FT_Long face_index,
2054  FT_Face *aface )
2055  {
2056  FT_Memory memory = library->memory;
2057  FT_Byte* sfnt_data = NULL;
2058  FT_Error error;
2059  FT_ULong flag_offset;
2060  FT_Long rlen;
2061  int is_cff;
2062  FT_Long face_index_in_resource = 0;
2063 
2064 
2065  if ( face_index < 0 )
2066  face_index = -face_index - 1;
2067  if ( face_index >= resource_cnt )
2068  return FT_THROW( Cannot_Open_Resource );
2069 
2070  flag_offset = (FT_ULong)offsets[face_index];
2071  error = FT_Stream_Seek( stream, flag_offset );
2072  if ( error )
2073  goto Exit;
2074 
2075  if ( FT_READ_LONG( rlen ) )
2076  goto Exit;
2077  if ( rlen < 1 )
2078  return FT_THROW( Cannot_Open_Resource );
2079  if ( (FT_ULong)rlen > FT_MAC_RFORK_MAX_LEN )
2080  return FT_THROW( Invalid_Offset );
2081 
2082  error = open_face_PS_from_sfnt_stream( library,
2083  stream,
2084  face_index,
2085  0, NULL,
2086  aface );
2087  if ( !error )
2088  goto Exit;
2089 
2090  /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
2091  error = FT_Stream_Seek( stream, flag_offset + 4 );
2092  if ( error )
2093  goto Exit;
2094 
2095  if ( FT_ALLOC( sfnt_data, rlen ) )
2096  return error;
2097  error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, (FT_ULong)rlen );
2098  if ( error ) {
2099  FT_FREE( sfnt_data );
2100  goto Exit;
2101  }
2102 
2103  is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
2104  error = open_face_from_buffer( library,
2105  sfnt_data,
2106  (FT_ULong)rlen,
2107  face_index_in_resource,
2108  is_cff ? "cff" : "truetype",
2109  aface );
2110 
2111  Exit:
2112  return error;
2113  }
2114 
2115 
2116  /* Check for a valid resource fork header, or a valid dfont */
2117  /* header. In a resource fork the first 16 bytes are repeated */
2118  /* at the location specified by bytes 4-7. In a dfont bytes */
2119  /* 4-7 point to 16 bytes of zeroes instead. */
2120  /* */
2121  static FT_Error
2122  IsMacResource( FT_Library library,
2123  FT_Stream stream,
2124  FT_Long resource_offset,
2125  FT_Long face_index,
2126  FT_Face *aface )
2127  {
2128  FT_Memory memory = library->memory;
2129  FT_Error error;
2130  FT_Long map_offset, rdata_pos;
2131  FT_Long *data_offsets;
2132  FT_Long count;
2133 
2134 
2135  error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
2136  &map_offset, &rdata_pos );
2137  if ( error )
2138  return error;
2139 
2140  /* POST resources must be sorted to concatenate properly */
2142  map_offset, rdata_pos,
2143  TTAG_POST, TRUE,
2144  &data_offsets, &count );
2145  if ( !error )
2146  {
2147  error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
2148  face_index, aface );
2149  FT_FREE( data_offsets );
2150  /* POST exists in an LWFN providing a single face */
2151  if ( !error )
2152  (*aface)->num_faces = 1;
2153  return error;
2154  }
2155 
2156  /* sfnt resources should not be sorted to preserve the face order by
2157  QuickDraw API */
2159  map_offset, rdata_pos,
2160  TTAG_sfnt, FALSE,
2161  &data_offsets, &count );
2162  if ( !error )
2163  {
2164  FT_Long face_index_internal = face_index % count;
2165 
2166 
2167  error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
2168  face_index_internal, aface );
2169  FT_FREE( data_offsets );
2170  if ( !error )
2171  (*aface)->num_faces = count;
2172  }
2173 
2174  return error;
2175  }
2176 
2177 
2178  /* Check for a valid macbinary header, and if we find one */
2179  /* check that the (flattened) resource fork in it is valid. */
2180  /* */
2181  static FT_Error
2182  IsMacBinary( FT_Library library,
2183  FT_Stream stream,
2184  FT_Long face_index,
2185  FT_Face *aface )
2186  {
2187  unsigned char header[128];
2188  FT_Error error;
2189  FT_Long dlen, offset;
2190 
2191 
2192  if ( !stream )
2193  return FT_THROW( Invalid_Stream_Operation );
2194 
2195  error = FT_Stream_Seek( stream, 0 );
2196  if ( error )
2197  goto Exit;
2198 
2199  error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
2200  if ( error )
2201  goto Exit;
2202 
2203  if ( header[ 0] != 0 ||
2204  header[74] != 0 ||
2205  header[82] != 0 ||
2206  header[ 1] == 0 ||
2207  header[ 1] > 33 ||
2208  header[63] != 0 ||
2209  header[2 + header[1]] != 0 ||
2210  header[0x53] > 0x7F )
2211  return FT_THROW( Unknown_File_Format );
2212 
2213  dlen = ( header[0x53] << 24 ) |
2214  ( header[0x54] << 16 ) |
2215  ( header[0x55] << 8 ) |
2216  header[0x56];
2217 #if 0
2218  rlen = ( header[0x57] << 24 ) |
2219  ( header[0x58] << 16 ) |
2220  ( header[0x59] << 8 ) |
2221  header[0x5A];
2222 #endif /* 0 */
2223  offset = 128 + ( ( dlen + 127 ) & ~127 );
2224 
2225  return IsMacResource( library, stream, offset, face_index, aface );
2226 
2227  Exit:
2228  return error;
2229  }
2230 
2231 
2232  static FT_Error
2233  load_face_in_embedded_rfork( FT_Library library,
2234  FT_Stream stream,
2235  FT_Long face_index,
2236  FT_Face *aface,
2237  const FT_Open_Args *args )
2238  {
2239 
2240 #undef FT_COMPONENT
2241 #define FT_COMPONENT raccess
2242 
2243  FT_Memory memory = library->memory;
2244  FT_Error error = FT_ERR( Unknown_File_Format );
2245  FT_UInt i;
2246 
2247  char* file_names[FT_RACCESS_N_RULES];
2248  FT_Long offsets[FT_RACCESS_N_RULES];
2250  FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */
2251 
2253  FT_Stream stream2 = NULL;
2254 
2255 
2257  args->pathname, file_names, offsets, errors );
2258 
2259  for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
2260  {
2261  is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i );
2262  if ( is_darwin_vfs && vfs_rfork_has_no_font )
2263  {
2264  FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
2265  " is already checked and"
2266  " no font is found\n",
2267  i ));
2268  continue;
2269  }
2270 
2271  if ( errors[i] )
2272  {
2273  FT_TRACE3(( "Error 0x%x has occurred in rule %d\n",
2274  errors[i], i ));
2275  continue;
2276  }
2277 
2278  args2.flags = FT_OPEN_PATHNAME;
2279  args2.pathname = file_names[i] ? file_names[i] : args->pathname;
2280 
2281  FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...",
2282  i, args2.pathname, offsets[i] ));
2283 
2284  error = FT_Stream_New( library, &args2, &stream2 );
2285  if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) )
2286  vfs_rfork_has_no_font = TRUE;
2287 
2288  if ( error )
2289  {
2290  FT_TRACE3(( "failed\n" ));
2291  continue;
2292  }
2293 
2294  error = IsMacResource( library, stream2, offsets[i],
2295  face_index, aface );
2296  FT_Stream_Free( stream2, 0 );
2297 
2298  FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
2299 
2300  if ( !error )
2301  break;
2302  else if ( is_darwin_vfs )
2303  vfs_rfork_has_no_font = TRUE;
2304  }
2305 
2306  for (i = 0; i < FT_RACCESS_N_RULES; i++)
2307  {
2308  if ( file_names[i] )
2309  FT_FREE( file_names[i] );
2310  }
2311 
2312  /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
2313  if ( error )
2314  error = FT_ERR( Unknown_File_Format );
2315 
2316  return error;
2317 
2318 #undef FT_COMPONENT
2319 #define FT_COMPONENT objs
2320 
2321  }
2322 
2323 
2324  /* Check for some macintosh formats without Carbon framework. */
2325  /* Is this a macbinary file? If so look at the resource fork. */
2326  /* Is this a mac dfont file? */
2327  /* Is this an old style resource fork? (in data) */
2328  /* Else call load_face_in_embedded_rfork to try extra rules */
2329  /* (defined in `ftrfork.c'). */
2330  /* */
2331  static FT_Error
2332  load_mac_face( FT_Library library,
2333  FT_Stream stream,
2334  FT_Long face_index,
2335  FT_Face *aface,
2336  const FT_Open_Args *args )
2337  {
2338  FT_Error error;
2339  FT_UNUSED( args );
2340 
2341 
2342  error = IsMacBinary( library, stream, face_index, aface );
2343  if ( FT_ERR_EQ( error, Unknown_File_Format ) )
2344  {
2345 
2346 #undef FT_COMPONENT
2347 #define FT_COMPONENT raccess
2348 
2349 #ifdef FT_DEBUG_LEVEL_TRACE
2350  FT_TRACE3(( "Try as dfont: " ));
2351  if ( !( args->flags & FT_OPEN_MEMORY ) )
2352  FT_TRACE3(( "%s ...", args->pathname ));
2353 #endif
2354 
2355  error = IsMacResource( library, stream, 0, face_index, aface );
2356 
2357  FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
2358 
2359 #undef FT_COMPONENT
2360 #define FT_COMPONENT objs
2361 
2362  }
2363 
2364  if ( ( FT_ERR_EQ( error, Unknown_File_Format ) ||
2365  FT_ERR_EQ( error, Invalid_Stream_Operation ) ) &&
2366  ( args->flags & FT_OPEN_PATHNAME ) )
2367  error = load_face_in_embedded_rfork( library, stream,
2368  face_index, aface, args );
2369  return error;
2370  }
2371 #endif
2372 
2373 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2374 
2375 
2376  /* documentation is in freetype.h */
2377 
2381  FT_Long face_index,
2382  FT_Face *aface )
2383  {
2384  return ft_open_face_internal( library, args, face_index, aface, 1 );
2385  }
2386 
2387 
2388  static FT_Error
2390  const FT_Open_Args* args,
2391  FT_Long face_index,
2392  FT_Face *aface,
2393  FT_Bool test_mac_fonts )
2394  {
2395  FT_Error error;
2396  FT_Driver driver = NULL;
2397  FT_Memory memory = NULL;
2398  FT_Stream stream = NULL;
2399  FT_Face face = NULL;
2400  FT_ListNode node = NULL;
2401  FT_Bool external_stream;
2402  FT_Module* cur;
2403  FT_Module* limit;
2404 
2405 #ifndef FT_CONFIG_OPTION_MAC_FONTS
2406  FT_UNUSED( test_mac_fonts );
2407 #endif
2408 
2409 
2410 #ifdef FT_DEBUG_LEVEL_TRACE
2411  FT_TRACE3(( "FT_Open_Face: " ));
2412  if ( face_index < 0 )
2413  FT_TRACE3(( "Requesting number of faces and named instances\n"));
2414  else
2415  {
2416  FT_TRACE3(( "Requesting face %ld", face_index & 0xFFFFL ));
2417  if ( face_index & 0x7FFF0000L )
2418  FT_TRACE3(( ", named instance %ld", face_index >> 16 ));
2419  FT_TRACE3(( "\n" ));
2420  }
2421 #endif
2422 
2423  /* test for valid `library' delayed to `FT_Stream_New' */
2424 
2425  if ( ( !aface && face_index >= 0 ) || !args )
2426  return FT_THROW( Invalid_Argument );
2427 
2428  external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
2429  args->stream );
2430 
2431  /* create input stream */
2433  if ( error )
2434  goto Fail3;
2435 
2436  memory = library->memory;
2437 
2438  /* If the font driver is specified in the `args' structure, use */
2439  /* it. Otherwise, we scan the list of registered drivers. */
2440  if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
2441  {
2442  driver = FT_DRIVER( args->driver );
2443 
2444  /* not all modules are drivers, so check... */
2445  if ( FT_MODULE_IS_DRIVER( driver ) )
2446  {
2447  FT_Int num_params = 0;
2449 
2450 
2451  if ( args->flags & FT_OPEN_PARAMS )
2452  {
2453  num_params = args->num_params;
2454  params = args->params;
2455  }
2456 
2457  error = open_face( driver, &stream, external_stream, face_index,
2458  num_params, params, &face );
2459  if ( !error )
2460  goto Success;
2461  }
2462  else
2463  error = FT_THROW( Invalid_Handle );
2464 
2465  FT_Stream_Free( stream, external_stream );
2466  goto Fail;
2467  }
2468  else
2469  {
2470  error = FT_ERR( Missing_Module );
2471 
2472  /* check each font driver for an appropriate format */
2473  cur = library->modules;
2475 
2476  for ( ; cur < limit; cur++ )
2477  {
2478  /* not all modules are font drivers, so check... */
2479  if ( FT_MODULE_IS_DRIVER( cur[0] ) )
2480  {
2481  FT_Int num_params = 0;
2483 
2484 
2485  driver = FT_DRIVER( cur[0] );
2486 
2487  if ( args->flags & FT_OPEN_PARAMS )
2488  {
2489  num_params = args->num_params;
2490  params = args->params;
2491  }
2492 
2493  error = open_face( driver, &stream, external_stream, face_index,
2494  num_params, params, &face );
2495  if ( !error )
2496  goto Success;
2497 
2498 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2499  if ( test_mac_fonts &&
2500  ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
2501  FT_ERR_EQ( error, Table_Missing ) )
2502  {
2503  /* TrueType but essential tables are missing */
2504  error = FT_Stream_Seek( stream, 0 );
2505  if ( error )
2506  break;
2507 
2508  error = open_face_PS_from_sfnt_stream( library,
2509  stream,
2510  face_index,
2511  num_params,
2512  params,
2513  aface );
2514  if ( !error )
2515  {
2516  FT_Stream_Free( stream, external_stream );
2517  return error;
2518  }
2519  }
2520 #endif
2521 
2522  if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
2523  goto Fail3;
2524  }
2525  }
2526 
2527  Fail3:
2528  /* If we are on the mac, and we get an */
2529  /* FT_Err_Invalid_Stream_Operation it may be because we have an */
2530  /* empty data fork, so we need to check the resource fork. */
2531  if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) &&
2532  FT_ERR_NEQ( error, Unknown_File_Format ) &&
2533  FT_ERR_NEQ( error, Invalid_Stream_Operation ) )
2534  goto Fail2;
2535 
2536 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2537  if ( test_mac_fonts )
2538  {
2539  error = load_mac_face( library, stream, face_index, aface, args );
2540  if ( !error )
2541  {
2542  /* We don't want to go to Success here. We've already done */
2543  /* that. On the other hand, if we succeeded we still need to */
2544  /* close this stream (we opened a different stream which */
2545  /* extracted the interesting information out of this stream */
2546  /* here. That stream will still be open and the face will */
2547  /* point to it). */
2548  FT_Stream_Free( stream, external_stream );
2549  return error;
2550  }
2551  }
2552 
2553  if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
2554  goto Fail2;
2555 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2556 
2557  /* no driver is able to handle this format */
2558  error = FT_THROW( Unknown_File_Format );
2559 
2560  Fail2:
2561  FT_Stream_Free( stream, external_stream );
2562  goto Fail;
2563  }
2564 
2565  Success:
2566  FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2567 
2568  /* add the face object to its driver's list */
2569  if ( FT_NEW( node ) )
2570  goto Fail;
2571 
2572  node->data = face;
2573  /* don't assume driver is the same as face->driver, so use */
2574  /* face->driver instead. */
2576 
2577  /* now allocate a glyph slot object for the face */
2578  FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2579 
2580  if ( face_index >= 0 )
2581  {
2583  if ( error )
2584  goto Fail;
2585 
2586  /* finally, allocate a size object for the face */
2587  {
2588  FT_Size size;
2589 
2590 
2591  FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2592 
2593  error = FT_New_Size( face, &size );
2594  if ( error )
2595  goto Fail;
2596 
2597  face->size = size;
2598  }
2599  }
2600 
2601  /* some checks */
2602 
2603  if ( FT_IS_SCALABLE( face ) )
2604  {
2605  if ( face->height < 0 )
2606  face->height = (FT_Short)-face->height;
2607 
2608  if ( !FT_HAS_VERTICAL( face ) )
2610  }
2611 
2612  if ( FT_HAS_FIXED_SIZES( face ) )
2613  {
2614  FT_Int i;
2615 
2616 
2617  for ( i = 0; i < face->num_fixed_sizes; i++ )
2618  {
2619  FT_Bitmap_Size* bsize = face->available_sizes + i;
2620 
2621 
2622  if ( bsize->height < 0 )
2623  bsize->height = -bsize->height;
2624  if ( bsize->x_ppem < 0 )
2625  bsize->x_ppem = -bsize->x_ppem;
2626  if ( bsize->y_ppem < 0 )
2627  bsize->y_ppem = -bsize->y_ppem;
2628 
2629  /* check whether negation actually has worked */
2630  if ( bsize->height < 0 || bsize->x_ppem < 0 || bsize->y_ppem < 0 )
2631  {
2632  FT_TRACE0(( "FT_Open_Face:"
2633  " Invalid bitmap dimensions for strike %d,"
2634  " now disabled\n", i ));
2635  bsize->width = 0;
2636  bsize->height = 0;
2637  bsize->size = 0;
2638  bsize->x_ppem = 0;
2639  bsize->y_ppem = 0;
2640  }
2641  }
2642  }
2643 
2644  /* initialize internal face data */
2645  {
2646  FT_Face_Internal internal = face->internal;
2647 
2648 
2649  internal->transform_matrix.xx = 0x10000L;
2650  internal->transform_matrix.xy = 0;
2651  internal->transform_matrix.yx = 0;
2652  internal->transform_matrix.yy = 0x10000L;
2653 
2654  internal->transform_delta.x = 0;
2655  internal->transform_delta.y = 0;
2656 
2657  internal->refcount = 1;
2658 
2659  internal->no_stem_darkening = -1;
2660 
2661 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
2662  /* Per-face filtering can only be set up by FT_Face_Properties */
2663  internal->lcd_filter_func = NULL;
2664 #endif
2665  }
2666 
2667  if ( aface )
2668  *aface = face;
2669  else
2670  FT_Done_Face( face );
2671 
2672  goto Exit;
2673 
2674  Fail:
2675  if ( node )
2676  FT_Done_Face( face ); /* face must be in the driver's list */
2677  else if ( face )
2678  destroy_face( memory, face, driver );
2679 
2680  Exit:
2681 #ifdef FT_DEBUG_LEVEL_TRACE
2682  if ( !error && face_index < 0 )
2683  {
2684  FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n"
2685  " and %ld named instance%s for face %ld\n",
2686  face->num_faces,
2687  face->num_faces == 1 ? "" : "s",
2688  face->style_flags >> 16,
2689  ( face->style_flags >> 16 ) == 1 ? "" : "s",
2690  -face_index - 1 ));
2691  }
2692 #endif
2693 
2694  FT_TRACE4(( "FT_Open_Face: Return 0x%x\n", error ));
2695 
2696  return error;
2697  }
2698 
2699 
2700  /* documentation is in freetype.h */
2701 
2704  const char* filepathname )
2705  {
2707 
2708 
2709  /* test for valid `face' delayed to `FT_Attach_Stream' */
2710 
2711  if ( !filepathname )
2712  return FT_THROW( Invalid_Argument );
2713 
2714  open.stream = NULL;
2715  open.flags = FT_OPEN_PATHNAME;
2716  open.pathname = (char*)filepathname;
2717 
2718  return FT_Attach_Stream( face, &open );
2719  }
2720 
2721 
2722  /* documentation is in freetype.h */
2723 
2727  {
2728  FT_Stream stream;
2729  FT_Error error;
2730  FT_Driver driver;
2731 
2732  FT_Driver_Class clazz;
2733 
2734 
2735  /* test for valid `parameters' delayed to `FT_Stream_New' */
2736 
2737  if ( !face )
2738  return FT_THROW( Invalid_Face_Handle );
2739 
2740  driver = face->driver;
2741  if ( !driver )
2742  return FT_THROW( Invalid_Driver_Handle );
2743 
2744  error = FT_Stream_New( driver->root.library, parameters, &stream );
2745  if ( error )
2746  goto Exit;
2747 
2748  /* we implement FT_Attach_Stream in each driver through the */
2749  /* `attach_file' interface */
2750 
2751  error = FT_ERR( Unimplemented_Feature );
2752  clazz = driver->clazz;
2753  if ( clazz->attach_file )
2754  error = clazz->attach_file( face, stream );
2755 
2756  /* close the attached stream */
2758  FT_BOOL( parameters->stream &&
2759  ( parameters->flags & FT_OPEN_STREAM ) ) );
2760 
2761  Exit:
2762  return error;
2763  }
2764 
2765 
2766  /* documentation is in freetype.h */
2767 
2770  {
2771  if ( !face )
2772  return FT_THROW( Invalid_Face_Handle );
2773 
2774  face->internal->refcount++;
2775 
2776  return FT_Err_Ok;
2777  }
2778 
2779 
2780  /* documentation is in freetype.h */
2781 
2784  {
2785  FT_Error error;
2786  FT_Driver driver;
2787  FT_Memory memory;
2788  FT_ListNode node;
2789 
2790 
2791  error = FT_ERR( Invalid_Face_Handle );
2792  if ( face && face->driver )
2793  {
2794  face->internal->refcount--;
2795  if ( face->internal->refcount > 0 )
2796  error = FT_Err_Ok;
2797  else
2798  {
2799  driver = face->driver;
2800  memory = driver->root.memory;
2801 
2802  /* find face in driver's list */
2803  node = FT_List_Find( &driver->faces_list, face );
2804  if ( node )
2805  {
2806  /* remove face object from the driver's list */
2807  FT_List_Remove( &driver->faces_list, node );
2808  FT_FREE( node );
2809 
2810  /* now destroy the object proper */
2811  destroy_face( memory, face, driver );
2812  error = FT_Err_Ok;
2813  }
2814  }
2815  }
2816 
2817  return error;
2818  }
2819 
2820 
2821  /* documentation is in ftobjs.h */
2822 
2825  FT_Size *asize )
2826  {
2827  FT_Error error;
2828  FT_Memory memory;
2829  FT_Driver driver;
2830  FT_Driver_Class clazz;
2831 
2832  FT_Size size = NULL;
2833  FT_ListNode node = NULL;
2834 
2835  FT_Size_Internal internal = NULL;
2836 
2837 
2838  if ( !face )
2839  return FT_THROW( Invalid_Face_Handle );
2840 
2841  if ( !asize )
2842  return FT_THROW( Invalid_Argument );
2843 
2844  if ( !face->driver )
2845  return FT_THROW( Invalid_Driver_Handle );
2846 
2847  *asize = NULL;
2848 
2849  driver = face->driver;
2850  clazz = driver->clazz;
2851  memory = face->memory;
2852 
2853  /* Allocate new size object and perform basic initialisation */
2854  if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
2855  goto Exit;
2856 
2857  size->face = face;
2858 
2859  if ( FT_NEW( internal ) )
2860  goto Exit;
2861 
2862  size->internal = internal;
2863 
2864  if ( clazz->init_size )
2865  error = clazz->init_size( size );
2866 
2867  /* in case of success, add to the face's list */
2868  if ( !error )
2869  {
2870  *asize = size;
2871  node->data = size;
2873  }
2874 
2875  Exit:
2876  if ( error )
2877  {
2878  FT_FREE( node );
2879  if ( size )
2880  FT_FREE( size->internal );
2881  FT_FREE( size );
2882  }
2883 
2884  return error;
2885  }
2886 
2887 
2888  /* documentation is in ftobjs.h */
2889 
2892  {
2893  FT_Error error;
2894  FT_Driver driver;
2895  FT_Memory memory;
2896  FT_Face face;
2897  FT_ListNode node;
2898 
2899 
2900  if ( !size )
2901  return FT_THROW( Invalid_Size_Handle );
2902 
2903  face = size->face;
2904  if ( !face )
2905  return FT_THROW( Invalid_Face_Handle );
2906 
2907  driver = face->driver;
2908  if ( !driver )
2909  return FT_THROW( Invalid_Driver_Handle );
2910 
2911  memory = driver->root.memory;
2912 
2913  error = FT_Err_Ok;
2915  if ( node )
2916  {
2918  FT_FREE( node );
2919 
2920  if ( face->size == size )
2921  {
2922  face->size = NULL;
2923  if ( face->sizes_list.head )
2925  }
2926 
2927  destroy_size( memory, size, driver );
2928  }
2929  else
2930  error = FT_THROW( Invalid_Size_Handle );
2931 
2932  return error;
2933  }
2934 
2935 
2936  /* documentation is in ftobjs.h */
2937 
2940  FT_Size_Request req,
2941  FT_Bool ignore_width,
2942  FT_ULong* size_index )
2943  {
2944  FT_Int i;
2945  FT_Long w, h;
2946 
2947 
2948  if ( !FT_HAS_FIXED_SIZES( face ) )
2949  return FT_THROW( Invalid_Face_Handle );
2950 
2951  /* FT_Bitmap_Size doesn't provide enough info... */
2952  if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
2953  return FT_THROW( Unimplemented_Feature );
2954 
2955  w = FT_REQUEST_WIDTH ( req );
2956  h = FT_REQUEST_HEIGHT( req );
2957 
2958  if ( req->width && !req->height )
2959  h = w;
2960  else if ( !req->width && req->height )
2961  w = h;
2962 
2963  w = FT_PIX_ROUND( w );
2964  h = FT_PIX_ROUND( h );
2965 
2966  if ( !w || !h )
2967  return FT_THROW( Invalid_Pixel_Size );
2968 
2969  for ( i = 0; i < face->num_fixed_sizes; i++ )
2970  {
2971  FT_Bitmap_Size* bsize = face->available_sizes + i;
2972 
2973 
2974  if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
2975  continue;
2976 
2977  if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
2978  {
2979  FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i ));
2980 
2981  if ( size_index )
2982  *size_index = (FT_ULong)i;
2983 
2984  return FT_Err_Ok;
2985  }
2986  }
2987 
2988  FT_TRACE3(( "FT_Match_Size: no matching bitmap strike\n" ));
2989 
2990  return FT_THROW( Invalid_Pixel_Size );
2991  }
2992 
2993 
2994  /* documentation is in ftobjs.h */
2995 
2996  FT_BASE_DEF( void )
2998  FT_Pos advance )
2999  {
3000  FT_Pos height = metrics->height;
3001 
3002 
3003  /* compensate for glyph with bbox above/below the baseline */
3004  if ( metrics->horiBearingY < 0 )
3005  {
3006  if ( height < metrics->horiBearingY )
3007  height = metrics->horiBearingY;
3008  }
3009  else if ( metrics->horiBearingY > 0 )
3010  height -= metrics->horiBearingY;
3011 
3012  /* the factor 1.2 is a heuristical value */
3013  if ( !advance )
3014  advance = height * 12 / 10;
3015 
3016  metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
3017  metrics->vertBearingY = ( advance - height ) / 2;
3018  metrics->vertAdvance = advance;
3019  }
3020 
3021 
3022  static void
3025  {
3026  /* Compute root ascender, descender, test height, and max_advance */
3027 
3028 #ifdef GRID_FIT_METRICS
3029  metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender,
3030  metrics->y_scale ) );
3031 
3032  metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender,
3033  metrics->y_scale ) );
3034 
3035  metrics->height = FT_PIX_ROUND( FT_MulFix( face->height,
3036  metrics->y_scale ) );
3037 
3039  metrics->x_scale ) );
3040 #else /* !GRID_FIT_METRICS */
3041  metrics->ascender = FT_MulFix( face->ascender,
3042  metrics->y_scale );
3043 
3044  metrics->descender = FT_MulFix( face->descender,
3045  metrics->y_scale );
3046 
3047  metrics->height = FT_MulFix( face->height,
3048  metrics->y_scale );
3049 
3050  metrics->max_advance = FT_MulFix( face->max_advance_width,
3051  metrics->x_scale );
3052 #endif /* !GRID_FIT_METRICS */
3053  }
3054 
3055 
3056  FT_BASE_DEF( void )
3058  FT_ULong strike_index )
3059  {
3061  FT_Bitmap_Size* bsize;
3062 
3063 
3064  metrics = &face->size->metrics;
3065  bsize = face->available_sizes + strike_index;
3066 
3067  metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
3068  metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
3069 
3070  if ( FT_IS_SCALABLE( face ) )
3071  {
3072  metrics->x_scale = FT_DivFix( bsize->x_ppem,
3073  face->units_per_EM );
3074  metrics->y_scale = FT_DivFix( bsize->y_ppem,
3075  face->units_per_EM );
3076 
3078  }
3079  else
3080  {
3081  metrics->x_scale = 1L << 16;
3082  metrics->y_scale = 1L << 16;
3083  metrics->ascender = bsize->y_ppem;
3084  metrics->descender = 0;
3085  metrics->height = bsize->height << 6;
3086  metrics->max_advance = bsize->x_ppem;
3087  }
3088  }
3089 
3090 
3091  FT_BASE_DEF( void )
3093  FT_Size_Request req )
3094  {
3096 
3097 
3098  metrics = &face->size->metrics;
3099 
3100  if ( FT_IS_SCALABLE( face ) )
3101  {
3102  FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0;
3103 
3104 
3105  switch ( req->type )
3106  {
3108  w = h = face->units_per_EM;
3109  break;
3110 
3112  w = h = face->ascender - face->descender;
3113  break;
3114 
3116  w = face->bbox.xMax - face->bbox.xMin;
3117  h = face->bbox.yMax - face->bbox.yMin;
3118  break;
3119 
3122  h = face->ascender - face->descender;
3123  break;
3124 
3126  metrics->x_scale = (FT_Fixed)req->width;
3127  metrics->y_scale = (FT_Fixed)req->height;
3128  if ( !metrics->x_scale )
3129  metrics->x_scale = metrics->y_scale;
3130  else if ( !metrics->y_scale )
3131  metrics->y_scale = metrics->x_scale;
3132  goto Calculate_Ppem;
3133 
3135  break;
3136  }
3137 
3138  /* to be on the safe side */
3139  if ( w < 0 )
3140  w = -w;
3141 
3142  if ( h < 0 )
3143  h = -h;
3144 
3145  scaled_w = FT_REQUEST_WIDTH ( req );
3146  scaled_h = FT_REQUEST_HEIGHT( req );
3147 
3148  /* determine scales */
3149  if ( req->width )
3150  {
3151  metrics->x_scale = FT_DivFix( scaled_w, w );
3152 
3153  if ( req->height )
3154  {
3155  metrics->y_scale = FT_DivFix( scaled_h, h );
3156 
3157  if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
3158  {
3159  if ( metrics->y_scale > metrics->x_scale )
3160  metrics->y_scale = metrics->x_scale;
3161  else
3162  metrics->x_scale = metrics->y_scale;
3163  }
3164  }
3165  else
3166  {
3167  metrics->y_scale = metrics->x_scale;
3168  scaled_h = FT_MulDiv( scaled_w, h, w );
3169  }
3170  }
3171  else
3172  {
3173  metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
3174  scaled_w = FT_MulDiv( scaled_h, w, h );
3175  }
3176 
3177  Calculate_Ppem:
3178  /* calculate the ppems */
3179  if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
3180  {
3181  scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
3182  scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
3183  }
3184 
3185  metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
3186  metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
3187 
3189  }
3190  else
3191  {
3192  FT_ZERO( metrics );
3193  metrics->x_scale = 1L << 16;
3194  metrics->y_scale = 1L << 16;
3195  }
3196  }
3197 
3198 
3199  /* documentation is in freetype.h */
3200 
3203  FT_Int strike_index )
3204  {
3206  FT_Driver_Class clazz;
3207 
3208 
3209  if ( !face || !FT_HAS_FIXED_SIZES( face ) )
3210  return FT_THROW( Invalid_Face_Handle );
3211 
3212  if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
3213  return FT_THROW( Invalid_Argument );
3214 
3215  clazz = face->driver->clazz;
3216 
3217  if ( clazz->select_size )
3218  {
3219  error = clazz->select_size( face->size, (FT_ULong)strike_index );
3220 
3221  FT_TRACE5(( "FT_Select_Size (%s driver):\n",
3223  }
3224  else
3225  {
3226  FT_Select_Metrics( face, (FT_ULong)strike_index );
3227 
3228  FT_TRACE5(( "FT_Select_Size:\n" ));
3229  }
3230 
3231 #ifdef FT_DEBUG_LEVEL_TRACE
3232  {
3234 
3235 
3236  FT_TRACE5(( " x scale: %ld (%f)\n",
3237  metrics->x_scale, metrics->x_scale / 65536.0 ));
3238  FT_TRACE5(( " y scale: %ld (%f)\n",
3239  metrics->y_scale, metrics->y_scale / 65536.0 ));
3240  FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
3241  FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
3242  FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
3243  FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
3244  FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
3245  FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
3246  }
3247 #endif
3248 
3249  return error;
3250  }
3251 
3252 
3253  /* documentation is in freetype.h */
3254 
3257  FT_Size_Request req )
3258  {
3260  FT_Driver_Class clazz;
3261  FT_ULong strike_index;
3262 
3263 
3264  if ( !face )
3265  return FT_THROW( Invalid_Face_Handle );
3266 
3267  if ( !req || req->width < 0 || req->height < 0 ||
3268  req->type >= FT_SIZE_REQUEST_TYPE_MAX )
3269  return FT_THROW( Invalid_Argument );
3270 
3271  /* signal the auto-hinter to recompute its size metrics */
3272  /* (if requested) */
3274 
3275  clazz = face->driver->clazz;
3276 
3277  if ( clazz->request_size )
3278  {
3279  error = clazz->request_size( face->size, req );
3280 
3281  FT_TRACE5(( "FT_Request_Size (%s driver):\n",
3283  }
3284  else if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
3285  {
3286  /*
3287  * The reason that a driver doesn't have `request_size' defined is
3288  * either that the scaling here suffices or that the supported formats
3289  * are bitmap-only and size matching is not implemented.
3290  *
3291  * In the latter case, a simple size matching is done.
3292  */
3293  error = FT_Match_Size( face, req, 0, &strike_index );
3294  if ( error )
3295  return error;
3296 
3297  return FT_Select_Size( face, (FT_Int)strike_index );
3298  }
3299  else
3300  {
3301  FT_Request_Metrics( face, req );
3302 
3303  FT_TRACE5(( "FT_Request_Size:\n" ));
3304  }
3305 
3306 #ifdef FT_DEBUG_LEVEL_TRACE
3307  {
3309 
3310 
3311  FT_TRACE5(( " x scale: %ld (%f)\n",
3312  metrics->x_scale, metrics->x_scale / 65536.0 ));
3313  FT_TRACE5(( " y scale: %ld (%f)\n",
3314  metrics->y_scale, metrics->y_scale / 65536.0 ));
3315  FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
3316  FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
3317  FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
3318  FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
3319  FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
3320  FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
3321  }
3322 #endif
3323 
3324  return error;
3325  }
3326 
3327 
3328  /* documentation is in freetype.h */
3329 
3334  FT_UInt horz_resolution,
3335  FT_UInt vert_resolution )
3336  {
3337  FT_Size_RequestRec req;
3338 
3339 
3340  /* check of `face' delayed to `FT_Request_Size' */
3341 
3342  if ( !char_width )
3344  else if ( !char_height )
3346 
3347  if ( !horz_resolution )
3348  horz_resolution = vert_resolution;
3349  else if ( !vert_resolution )
3350  vert_resolution = horz_resolution;
3351 
3352  if ( char_width < 1 * 64 )
3353  char_width = 1 * 64;
3354  if ( char_height < 1 * 64 )
3355  char_height = 1 * 64;
3356 
3357  if ( !horz_resolution )
3358  horz_resolution = vert_resolution = 72;
3359 
3361  req.width = char_width;
3362  req.height = char_height;
3363  req.horiResolution = horz_resolution;
3364  req.vertResolution = vert_resolution;
3365 
3366  return FT_Request_Size( face, &req );
3367  }
3368 
3369 
3370  /* documentation is in freetype.h */
3371 
3374  FT_UInt pixel_width,
3375  FT_UInt pixel_height )
3376  {
3377  FT_Size_RequestRec req;
3378 
3379 
3380  /* check of `face' delayed to `FT_Request_Size' */
3381 
3382  if ( pixel_width == 0 )
3383  pixel_width = pixel_height;
3384  else if ( pixel_height == 0 )
3385  pixel_height = pixel_width;
3386 
3387  if ( pixel_width < 1 )
3388  pixel_width = 1;
3389  if ( pixel_height < 1 )
3390  pixel_height = 1;
3391 
3392  /* use `>=' to avoid potential compiler warning on 16bit platforms */
3393  if ( pixel_width >= 0xFFFFU )
3394  pixel_width = 0xFFFFU;
3395  if ( pixel_height >= 0xFFFFU )
3396  pixel_height = 0xFFFFU;
3397 
3399  req.width = (FT_Long)( pixel_width << 6 );
3400  req.height = (FT_Long)( pixel_height << 6 );
3401  req.horiResolution = 0;
3402  req.vertResolution = 0;
3403 
3404  return FT_Request_Size( face, &req );
3405  }
3406 
3407 
3408  /* documentation is in freetype.h */
3409 
3414  FT_UInt kern_mode,
3415  FT_Vector *akerning )
3416  {
3418  FT_Driver driver;
3419 
3420 
3421  if ( !face )
3422  return FT_THROW( Invalid_Face_Handle );
3423 
3424  if ( !akerning )
3425  return FT_THROW( Invalid_Argument );
3426 
3427  driver = face->driver;
3428 
3429  akerning->x = 0;
3430  akerning->y = 0;
3431 
3432  if ( driver->clazz->get_kerning )
3433  {
3434  error = driver->clazz->get_kerning( face,
3435  left_glyph,
3436  right_glyph,
3437  akerning );
3438  if ( !error )
3439  {
3440  if ( kern_mode != FT_KERNING_UNSCALED )
3441  {
3442  akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
3443  akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
3444 
3445  if ( kern_mode != FT_KERNING_UNFITTED )
3446  {
3447  FT_Pos orig_x = akerning->x;
3448  FT_Pos orig_y = akerning->y;
3449 
3450 
3451  /* we scale down kerning values for small ppem values */
3452  /* to avoid that rounding makes them too big. */
3453  /* `25' has been determined heuristically. */
3454  if ( face->size->metrics.x_ppem < 25 )
3455  akerning->x = FT_MulDiv( orig_x,
3456  face->size->metrics.x_ppem, 25 );
3457  if ( face->size->metrics.y_ppem < 25 )
3458  akerning->y = FT_MulDiv( orig_y,
3459  face->size->metrics.y_ppem, 25 );
3460 
3461  akerning->x = FT_PIX_ROUND( akerning->x );
3462  akerning->y = FT_PIX_ROUND( akerning->y );
3463 
3464 #ifdef FT_DEBUG_LEVEL_TRACE
3465  {
3466  FT_Pos orig_x_rounded = FT_PIX_ROUND( orig_x );
3467  FT_Pos orig_y_rounded = FT_PIX_ROUND( orig_y );
3468 
3469 
3470  if ( akerning->x != orig_x_rounded ||
3471  akerning->y != orig_y_rounded )
3472  FT_TRACE5(( "FT_Get_Kerning: horizontal kerning"
3473  " (%ld, %ld) scaled down to (%ld, %ld) pixels\n",
3474  orig_x_rounded / 64, orig_y_rounded / 64,
3475  akerning->x / 64, akerning->y / 64 ));
3476  }
3477 #endif
3478  }
3479  }
3480  }
3481  }
3482 
3483  return error;
3484  }
3485 
3486 
3487  /* documentation is in freetype.h */
3488 
3492  FT_Int degree,
3493  FT_Fixed* akerning )
3494  {
3495  FT_Service_Kerning service;
3497 
3498 
3499  if ( !face )
3500  return FT_THROW( Invalid_Face_Handle );
3501 
3502  if ( !akerning )
3503  return FT_THROW( Invalid_Argument );
3504 
3505  FT_FACE_FIND_SERVICE( face, service, KERNING );
3506  if ( !service )
3507  return FT_THROW( Unimplemented_Feature );
3508 
3509  error = service->get_track( face,
3510  point_size,
3511  degree,
3512  akerning );
3513 
3514  return error;
3515  }
3516 
3517 
3518  /* documentation is in freetype.h */
3519 
3523  {
3524  FT_CharMap* cur;
3525  FT_CharMap* limit;
3526 
3527 
3528  if ( !face )
3529  return FT_THROW( Invalid_Face_Handle );
3530 
3531  /* FT_ENCODING_NONE is a valid encoding for BDF, PCF, and Windows FNT */
3533  return FT_THROW( Invalid_Argument );
3534 
3535  /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
3536  /* charmap available, i.e., one with UCS-4 characters, if possible. */
3537  /* */
3538  /* This is done by find_unicode_charmap() above, to share code. */
3539  if ( encoding == FT_ENCODING_UNICODE )
3540  return find_unicode_charmap( face );
3541 
3542  cur = face->charmaps;
3543  if ( !cur )
3544  return FT_THROW( Invalid_CharMap_Handle );
3545 
3546  limit = cur + face->num_charmaps;
3547 
3548  for ( ; cur < limit; cur++ )
3549  {
3550  if ( cur[0]->encoding == encoding )
3551  {
3552  face->charmap = cur[0];
3553  return FT_Err_Ok;
3554  }
3555  }
3556 
3557  return FT_THROW( Invalid_Argument );
3558  }
3559 
3560 
3561  /* documentation is in freetype.h */
3562 
3566  {
3567  FT_CharMap* cur;
3568  FT_CharMap* limit;
3569 
3570 
3571  if ( !face )
3572  return FT_THROW( Invalid_Face_Handle );
3573 
3574  cur = face->charmaps;
3575  if ( !cur || !charmap )
3576  return FT_THROW( Invalid_CharMap_Handle );
3577 
3578  limit = cur + face->num_charmaps;
3579 
3580  for ( ; cur < limit; cur++ )
3581  {
3582  if ( cur[0] == charmap &&
3583  FT_Get_CMap_Format ( charmap ) != 14 )
3584  {
3585  face->charmap = cur[0];
3586  return FT_Err_Ok;
3587  }
3588  }
3589 
3590  return FT_THROW( Invalid_Argument );
3591  }
3592 
3593 
3594  /* documentation is in freetype.h */
3595 
3598  {
3599  FT_Int i;
3600 
3601 
3602  if ( !charmap || !charmap->face )
3603  return -1;
3604 
3605  for ( i = 0; i < charmap->face->num_charmaps; i++ )
3606  if ( charmap->face->charmaps[i] == charmap )
3607  break;
3608 
3609  FT_ASSERT( i < charmap->face->num_charmaps );
3610 
3611  return i;
3612  }
3613 
3614 
3615  static void
3617  {
3618  FT_CMap_Class clazz = cmap->clazz;
3619  FT_Face face = cmap->charmap.face;
3620  FT_Memory memory = FT_FACE_MEMORY( face );
3621 
3622 
3623  if ( clazz->done )
3624  clazz->done( cmap );
3625 
3626  FT_FREE( cmap );
3627  }
3628 
3629 
3630  FT_BASE_DEF( void )
3632  {
3633  if ( cmap )
3634  {
3635  FT_Face face = cmap->charmap.face;
3636  FT_Memory memory = FT_FACE_MEMORY( face );
3637  FT_Error error;
3638  FT_Int i, j;
3639 
3640 
3641  for ( i = 0; i < face->num_charmaps; i++ )
3642  {
3643  if ( (FT_CMap)face->charmaps[i] == cmap )
3644  {
3645  FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1];
3646 
3647 
3648  if ( FT_RENEW_ARRAY( face->charmaps,
3649  face->num_charmaps,
3650  face->num_charmaps - 1 ) )
3651  return;
3652 
3653  /* remove it from our list of charmaps */
3654  for ( j = i + 1; j < face->num_charmaps; j++ )
3655  {
3656  if ( j == face->num_charmaps - 1 )
3657  face->charmaps[j - 1] = last_charmap;
3658  else
3659  face->charmaps[j - 1] = face->charmaps[j];
3660  }
3661 
3662  face->num_charmaps--;
3663 
3664  if ( (FT_CMap)face->charmap == cmap )
3665  face->charmap = NULL;
3666 
3668 
3669  break;
3670  }
3671  }
3672  }
3673  }
3674 
3675 
3678  FT_Pointer init_data,
3680  FT_CMap *acmap )
3681  {
3683  FT_Face face;
3684  FT_Memory memory;
3685  FT_CMap cmap = NULL;
3686 
3687 
3688  if ( !clazz || !charmap || !charmap->face )
3689  return FT_THROW( Invalid_Argument );
3690 
3691  face = charmap->face;
3692  memory = FT_FACE_MEMORY( face );
3693 
3694  if ( !FT_ALLOC( cmap, clazz->size ) )
3695  {
3696  cmap->charmap = *charmap;
3697  cmap->clazz = clazz;
3698 
3699  if ( clazz->init )
3700  {
3701  error = clazz->init( cmap, init_data );
3702  if ( error )
3703  goto Fail;
3704  }
3705 
3706  /* add it to our list of charmaps */
3707  if ( FT_RENEW_ARRAY( face->charmaps,
3708  face->num_charmaps,
3709  face->num_charmaps + 1 ) )
3710  goto Fail;
3711 
3713  }
3714 
3715  Exit:
3716  if ( acmap )
3717  *acmap = cmap;
3718 
3719  return error;
3720 
3721  Fail:
3723  cmap = NULL;
3724  goto Exit;
3725  }
3726 
3727 
3728  /* documentation is in freetype.h */
3729 
3732  FT_ULong charcode )
3733  {
3734  FT_UInt result = 0;
3735 
3736 
3737  if ( face && face->charmap )
3738  {
3740 
3741 
3742  if ( charcode > 0xFFFFFFFFUL )
3743  {
3744  FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3745  FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
3746  }
3747 
3748  result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
3749  if ( result >= (FT_UInt)face->num_glyphs )
3750  result = 0;
3751  }
3752 
3753  return result;
3754  }
3755 
3756 
3757  /* documentation is in freetype.h */
3758 
3761  FT_UInt *agindex )
3762  {
3763  FT_ULong result = 0;
3764  FT_UInt gindex = 0;
3765 
3766 
3767  /* only do something if we have a charmap, and we have glyphs at all */
3768  if ( face && face->charmap && face->num_glyphs )
3769  {
3770  gindex = FT_Get_Char_Index( face, 0 );
3771  if ( gindex == 0 )
3772  result = FT_Get_Next_Char( face, 0, &gindex );
3773  }
3774 
3775  if ( agindex )
3776  *agindex = gindex;
3777 
3778  return result;
3779  }
3780 
3781 
3782  /* documentation is in freetype.h */
3783 
3786  FT_ULong charcode,
3787  FT_UInt *agindex )
3788  {
3789  FT_ULong result = 0;
3790  FT_UInt gindex = 0;
3791 
3792 
3793  if ( face && face->charmap && face->num_glyphs )
3794  {
3795  FT_UInt32 code = (FT_UInt32)charcode;
3797 
3798 
3799  do
3800  {
3801  gindex = cmap->clazz->char_next( cmap, &code );
3802 
3803  } while ( gindex >= (FT_UInt)face->num_glyphs );
3804 
3805  result = ( gindex == 0 ) ? 0 : code;
3806  }
3807 
3808  if ( agindex )
3809  *agindex = gindex;
3810 
3811  return result;
3812  }
3813 
3814 
3815  /* documentation is in freetype.h */
3816 
3819  FT_UInt num_properties,
3821  {
3823 
3824 
3825  if ( num_properties > 0 && !properties )
3826  {
3827  error = FT_THROW( Invalid_Argument );
3828  goto Exit;
3829  }
3830 
3831  for ( ; num_properties > 0; num_properties-- )
3832  {
3834  {
3835  if ( properties->data )
3836  {
3837  if ( *( (FT_Bool*)properties->data ) == TRUE )
3839  else
3841  }
3842  else
3843  {
3844  /* use module default */
3846  }
3847  }
3848  else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS )
3849  {
3850 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
3851  if ( properties->data )
3852  {
3853  ft_memcpy( face->internal->lcd_weights,
3854  properties->data,
3856  face->internal->lcd_filter_func = ft_lcd_filter_fir;
3857  }
3858 #else
3859  error = FT_THROW( Unimplemented_Feature );
3860  goto Exit;
3861 #endif
3862  }
3863  else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED )
3864  {
3865  if ( properties->data )
3866  {
3867  face->internal->random_seed = *( (FT_Int32*)properties->data );
3868  if ( face->internal->random_seed < 0 )
3869  face->internal->random_seed = 0;
3870  }
3871  else
3872  {
3873  /* use module default */
3874  face->internal->random_seed = -1;
3875  }
3876  }
3877  else
3878  {
3879  error = FT_THROW( Invalid_Argument );
3880  goto Exit;
3881  }
3882 
3883  if ( error )
3884  break;
3885 
3886  properties++;
3887  }
3888 
3889  Exit:
3890  return error;
3891  }
3892 
3893 
3894  /* documentation is in freetype.h */
3895 
3898  FT_ULong charcode,
3899  FT_ULong variantSelector )
3900  {
3901  FT_UInt result = 0;
3902 
3903 
3904  if ( face &&
3905  face->charmap &&
3907  {
3909  FT_CMap ucmap = FT_CMAP( face->charmap );
3910 
3911 
3912  if ( charmap )
3913  {
3914  FT_CMap vcmap = FT_CMAP( charmap );
3915 
3916 
3917  if ( charcode > 0xFFFFFFFFUL )
3918  {
3919  FT_TRACE1(( "FT_Face_GetCharVariantIndex:"
3920  " too large charcode" ));
3921  FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
3922  }
3923  if ( variantSelector > 0xFFFFFFFFUL )
3924  {
3925  FT_TRACE1(( "FT_Face_GetCharVariantIndex:"
3926  " too large variantSelector" ));
3927  FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
3928  }
3929 
3930  result = vcmap->clazz->char_var_index( vcmap, ucmap,
3931  (FT_UInt32)charcode,
3932  (FT_UInt32)variantSelector );
3933  }
3934  }
3935 
3936  return result;
3937  }
3938 
3939 
3940  /* documentation is in freetype.h */
3941 
3944  FT_ULong charcode,
3945  FT_ULong variantSelector )
3946  {
3947  FT_Int result = -1;
3948 
3949 
3950  if ( face )
3951  {
3953 
3954 
3955  if ( charmap )
3956  {
3957  FT_CMap vcmap = FT_CMAP( charmap );
3958 
3959 
3960  if ( charcode > 0xFFFFFFFFUL )
3961  {
3962  FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:"
3963  " too large charcode" ));
3964  FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
3965  }
3966  if ( variantSelector > 0xFFFFFFFFUL )
3967  {
3968  FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:"
3969  " too large variantSelector" ));
3970  FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
3971  }
3972 
3973  result = vcmap->clazz->char_var_default( vcmap,
3974  (FT_UInt32)charcode,
3975  (FT_UInt32)variantSelector );
3976  }
3977  }
3978 
3979  return result;
3980  }
3981 
3982 
3983  /* documentation is in freetype.h */
3984 
3985  FT_EXPORT_DEF( FT_UInt32* )
3987  {
3988  FT_UInt32 *result = NULL;
3989 
3990 
3991  if ( face )
3992  {
3994 
3995 
3996  if ( charmap )
3997  {
3998  FT_CMap vcmap = FT_CMAP( charmap );
3999  FT_Memory memory = FT_FACE_MEMORY( face );
4000 
4001 
4002  result = vcmap->clazz->variant_list( vcmap, memory );
4003  }
4004  }
4005 
4006  return result;
4007  }
4008 
4009 
4010  /* documentation is in freetype.h */
4011 
4012  FT_EXPORT_DEF( FT_UInt32* )
4014  FT_ULong charcode )
4015  {
4016  FT_UInt32 *result = NULL;
4017 
4018 
4019  if ( face )
4020  {
4022 
4023 
4024  if ( charmap )
4025  {
4026  FT_CMap vcmap = FT_CMAP( charmap );
4027  FT_Memory memory = FT_FACE_MEMORY( face );
4028 
4029 
4030  if ( charcode > 0xFFFFFFFFUL )
4031  {
4032  FT_TRACE1(( "FT_Face_GetVariantsOfChar: too large charcode" ));
4033  FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
4034  }
4035 
4036  result = vcmap->clazz->charvariant_list( vcmap, memory,
4037  (FT_UInt32)charcode );
4038  }
4039  }
4040  return result;
4041  }
4042 
4043 
4044  /* documentation is in freetype.h */
4045 
4046  FT_EXPORT_DEF( FT_UInt32* )
4048  FT_ULong variantSelector )
4049  {
4050  FT_UInt32 *result = NULL;
4051 
4052 
4053  if ( face )
4054  {
4056 
4057 
4058  if ( charmap )
4059  {
4060  FT_CMap vcmap = FT_CMAP( charmap );
4061  FT_Memory memory = FT_FACE_MEMORY( face );
4062 
4063 
4064  if ( variantSelector > 0xFFFFFFFFUL )
4065  {
4066  FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
4067  FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
4068  }
4069 
4070  result = vcmap->clazz->variantchar_list( vcmap, memory,
4071  (FT_UInt32)variantSelector );
4072  }
4073  }
4074 
4075  return result;
4076  }
4077 
4078 
4079  /* documentation is in freetype.h */
4080 
4083  const FT_String* glyph_name )
4084  {
4085  FT_UInt result = 0;
4086 
4087 
4088  if ( face &&
4089  FT_HAS_GLYPH_NAMES( face ) &&
4090  glyph_name )
4091  {
4092  FT_Service_GlyphDict service;
4093 
4094 
4096  service,
4097  GLYPH_DICT );
4098 
4099  if ( service && service->name_index )
4100  result = service->name_index( face, glyph_name );
4101  }
4102 
4103  return result;
4104  }
4105 
4106 
4107  /* documentation is in freetype.h */
4108 
4113  FT_UInt buffer_max )
4114  {
4115  FT_Error error;
4116  FT_Service_GlyphDict service;
4117 
4118 
4119  if ( !face )
4120  return FT_THROW( Invalid_Face_Handle );
4121 
4122  if ( !buffer || buffer_max == 0 )
4123  return FT_THROW( Invalid_Argument );
4124 
4125  /* clean up buffer */
4126  ((FT_Byte*)buffer)[0] = '\0';
4127 
4128  if ( (FT_Long)glyph_index >= face->num_glyphs )
4129  return FT_THROW( Invalid_Glyph_Index );
4130 
4131  if ( !FT_HAS_GLYPH_NAMES( face ) )
4132  return FT_THROW( Invalid_Argument );
4133 
4134  FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT );
4135  if ( service && service->get_name )
4136  error = service->get_name( face, glyph_index, buffer, buffer_max );
4137  else
4138  error = FT_THROW( Invalid_Argument );
4139 
4140  return error;
4141  }
4142 
4143 
4144  /* documentation is in freetype.h */
4145 
4146  FT_EXPORT_DEF( const char* )
4148  {
4149  const char* result = NULL;
4150 
4151 
4152  if ( !face )
4153  goto Exit;
4154 
4155  if ( !result )
4156  {
4157  FT_Service_PsFontName service;
4158 
4159 
4161  service,
4162  POSTSCRIPT_FONT_NAME );
4163 
4164  if ( service && service->get_ps_font_name )
4165  result = service->get_ps_font_name( face );
4166  }
4167 
4168  Exit:
4169  return result;
4170  }
4171 
4172 
4173  /* documentation is in tttables.h */
4174 
4175  FT_EXPORT_DEF( void* )
4177  FT_Sfnt_Tag tag )
4178  {
4179  void* table = NULL;
4180  FT_Service_SFNT_Table service;
4181 
4182 
4183  if ( face && FT_IS_SFNT( face ) )
4184  {
4185  FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
4186  if ( service )
4187  table = service->get_table( face, tag );
4188  }
4189 
4190  return table;
4191  }
4192 
4193 
4194  /* documentation is in tttables.h */
4195 
4198  FT_ULong tag,
4199  FT_Long offset,
4200  FT_Byte* buffer,
4201  FT_ULong* length )
4202  {
4203  FT_Service_SFNT_Table service;
4204 
4205 
4206  if ( !face || !FT_IS_SFNT( face ) )
4207  return FT_THROW( Invalid_Face_Handle );
4208 
4209  FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
4210  if ( !service )
4211  return FT_THROW( Unimplemented_Feature );
4212 
4213  return service->load_table( face, tag, offset, buffer, length );
4214  }
4215 
4216 
4217  /* documentation is in tttables.h */
4218 
4221  FT_UInt table_index,
4222  FT_ULong *tag,
4223  FT_ULong *length )
4224  {
4225  FT_Service_SFNT_Table service;
4226  FT_ULong offset;
4227 
4228 
4229  /* test for valid `length' delayed to `service->table_info' */
4230 
4231  if ( !face || !FT_IS_SFNT( face ) )
4232  return FT_THROW( Invalid_Face_Handle );
4233 
4234  FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
4235  if ( !service )
4236  return FT_THROW( Unimplemented_Feature );
4237 
4238  return service->table_info( face, table_index, tag, &offset, length );
4239  }
4240 
4241 
4242  /* documentation is in tttables.h */
4243 
4246  {
4247  FT_Service_TTCMaps service;
4248  FT_Face face;
4250 
4251 
4252  if ( !charmap || !charmap->face )
4253  return 0;
4254 
4255  face = charmap->face;
4256  FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
4257  if ( !service )
4258  return 0;
4259  if ( service->get_cmap_info( charmap, &cmap_info ))
4260  return 0;
4261 
4262  return cmap_info.language;
4263  }
4264 
4265 
4266  /* documentation is in tttables.h */
4267 
4270  {
4271  FT_Service_TTCMaps service;
4272  FT_Face face;
4274 
4275 
4276  if ( !charmap || !charmap->face )
4277  return -1;
4278 
4279  face = charmap->face;
4280  FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
4281  if ( !service )
4282  return -1;
4283  if ( service->get_cmap_info( charmap, &cmap_info ))
4284  return -1;
4285 
4286  return cmap_info.format;
4287  }
4288 
4289 
4290  /* documentation is in ftsizes.h */
4291 
4294  {
4295  FT_Face face;
4296 
4297 
4298  if ( !size )
4299  return FT_THROW( Invalid_Size_Handle );
4300 
4301  face = size->face;
4302  if ( !face || !face->driver )
4303  return FT_THROW( Invalid_Face_Handle );
4304 
4305  /* we don't need anything more complex than that; all size objects */
4306  /* are already listed by the face */
4307  face->size = size;
4308 
4309  return FT_Err_Ok;
4310  }
4311 
4312 
4313  /*************************************************************************/
4314  /*************************************************************************/
4315  /*************************************************************************/
4316  /**** ****/
4317  /**** ****/
4318  /**** R E N D E R E R S ****/
4319  /**** ****/
4320  /**** ****/
4321  /*************************************************************************/
4322  /*************************************************************************/
4323  /*************************************************************************/
4324 
4325  /* lookup a renderer by glyph format in the library's list */
4329  FT_ListNode* node )
4330  {
4331  FT_ListNode cur;
4333 
4334 
4335  if ( !library )
4336  goto Exit;
4337 
4339 
4340  if ( node )
4341  {
4342  if ( *node )
4343  cur = (*node)->next;
4344  *node = NULL;
4345  }
4346 
4347  while ( cur )
4348  {
4349  FT_Renderer renderer = FT_RENDERER( cur->data );
4350 
4351 
4352  if ( renderer->glyph_format == format )
4353  {
4354  if ( node )
4355  *node = cur;
4356 
4357  result = renderer;
4358  break;
4359  }
4360  cur = cur->next;
4361  }
4362 
4363  Exit:
4364  return result;
4365  }
4366 
4367 
4368  static FT_Renderer
4370  {
4371  FT_Face face = slot->face;
4374 
4375 
4376  if ( !result || result->glyph_format != slot->format )
4377  result = FT_Lookup_Renderer( library, slot->format, 0 );
4378 
4379  return result;
4380  }
4381 
4382 
4383  static void
4385  {
4386  FT_Renderer renderer;
4387 
4388 
4390  library->cur_renderer = renderer;
4391  }
4392 
4393 
4394  static FT_Error
4396  {
4397  FT_Library library = module->library;
4398  FT_Memory memory = library->memory;
4399  FT_Error error;
4400  FT_ListNode node = NULL;
4401 
4402 
4403  if ( FT_NEW( node ) )
4404  goto Exit;
4405 
4406  {
4408  FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz;
4409 
4410 
4411  render->clazz = clazz;
4412  render->glyph_format = clazz->glyph_format;
4413 
4414  /* allocate raster object if needed */
4415  if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
4416  clazz->raster_class->raster_new )
4417  {
4418  error = clazz->raster_class->raster_new( memory, &render->raster );
4419  if ( error )
4420  goto Fail;
4421 
4422  render->raster_render = clazz->raster_class->raster_render;
4423  render->render = clazz->render_glyph;
4424  }
4425 
4426  /* add to list */
4427  node->data = module;
4429 
4431  }
4432 
4433  Fail:
4434  if ( error )
4435  FT_FREE( node );
4436 
4437  Exit:
4438  return error;
4439  }
4440 
4441 
4442  static void
4444  {
4446  FT_Memory memory;
4447  FT_ListNode node;
4448 
4449 
4450  library = module->library;
4451  if ( !library )
4452  return;
4453 
4454  memory = library->memory;
4455 
4457  if ( node )
4458  {
4460 
4461 
4462  /* release raster object, if any */
4463  if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
4464  render->raster )
4465  render->clazz->raster_class->raster_done( render->raster );
4466 
4467  /* remove from list */
4469  FT_FREE( node );
4470 
4472  }
4473  }
4474 
4475 
4476  /* documentation is in ftrender.h */
4477 
4481  {
4482  /* test for valid `library' delayed to `FT_Lookup_Renderer' */
4483 
4484  return FT_Lookup_Renderer( library, format, 0 );
4485  }
4486 
4487 
4488  /* documentation is in ftrender.h */
4489 
4492  FT_Renderer renderer,
4493  FT_UInt num_params,
4495  {
4496  FT_ListNode node;
4498 
4499  FT_Renderer_SetModeFunc set_mode;
4500 
4501 
4502  if ( !library )
4503  {
4504  error = FT_THROW( Invalid_Library_Handle );
4505  goto Exit;
4506  }
4507 
4508  if ( !renderer )
4509  {
4510  error = FT_THROW( Invalid_Argument );
4511  goto Exit;
4512  }
4513 
4514  if ( num_params > 0 && !parameters )
4515  {
4516  error = FT_THROW( Invalid_Argument );
4517  goto Exit;
4518  }
4519 
4520  node = FT_List_Find( &library->renderers, renderer );
4521  if ( !node )
4522  {
4523  error = FT_THROW( Invalid_Argument );
4524  goto Exit;
4525  }
4526 
4528 
4529  if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
4530  library->cur_renderer = renderer;
4531 
4532  set_mode = renderer->clazz->set_mode;
4533 
4534  for ( ; num_params > 0; num_params-- )
4535  {
4536  error = set_mode( renderer, parameters->tag, parameters->data );
4537  if ( error )
4538  break;
4539  parameters++;
4540  }
4541 
4542  Exit:
4543  return error;
4544  }
4545 
4546 
4550  FT_Render_Mode render_mode )
4551  {
4553  FT_Face face = slot->face;
4554  FT_Renderer renderer;
4555 
4556 
4557  switch ( slot->format )
4558  {
4559  case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */
4560  break;
4561 
4562  default:
4563  if ( slot->internal->load_flags & FT_LOAD_COLOR )
4564  {
4565  FT_LayerIterator iterator;
4566 
4567  FT_UInt base_glyph = slot->glyph_index;
4568 
4569  FT_Bool have_layers;
4571  FT_UInt color_index;
4572 
4573 
4574  /* check whether we have colored glyph layers */
4575  iterator.p = NULL;
4576  have_layers = FT_Get_Color_Glyph_Layer( face,
4577  base_glyph,
4578  &glyph_index,
4579  &color_index,
4580  &iterator );
4581  if ( have_layers )
4582  {
4584  if ( !error )
4585  {
4586  TT_Face ttface = (TT_Face)face;
4587  SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
4588 
4589 
4590  do
4591  {
4592  FT_Int32 load_flags = slot->internal->load_flags;
4593 
4594 
4595  /* disable the `FT_LOAD_COLOR' flag to avoid recursion */
4596  /* right here in this function */
4597  load_flags &= ~FT_LOAD_COLOR;
4598 
4599  /* render into the new `face->glyph' glyph slot */
4600  load_flags |= FT_LOAD_RENDER;
4601 
4602  error = FT_Load_Glyph( face, glyph_index, load_flags );
4603  if ( error )
4604  break;
4605 
4606  /* blend new `face->glyph' into old `slot'; */
4607  /* at the first call, `slot' is still empty */
4608  error = sfnt->colr_blend( ttface,
4609  color_index,
4610  slot,
4611  face->glyph );
4612  if ( error )
4613  break;
4614 
4615  } while ( FT_Get_Color_Glyph_Layer( face,
4616  base_glyph,
4617  &glyph_index,
4618  &color_index,
4619  &iterator ) );
4620 
4621  if ( !error )
4622  slot->format = FT_GLYPH_FORMAT_BITMAP;
4623 
4624  /* this call also restores `slot' as the glyph slot */
4626  }
4627 
4628  if ( !error )
4629  return error;
4630 
4631  /* Failed to do the colored layer. Draw outline instead. */
4632  slot->format = FT_GLYPH_FORMAT_OUTLINE;
4633  }
4634  }
4635 
4636  {
4637  FT_ListNode node = NULL;
4638 
4639 
4640  /* small shortcut for the very common case */
4641  if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
4642  {
4643  renderer = library->cur_renderer;
4645  }
4646  else
4647  renderer = FT_Lookup_Renderer( library, slot->format, &node );
4648 
4649  error = FT_ERR( Unimplemented_Feature );
4650  while ( renderer )
4651  {
4652  error = renderer->render( renderer, slot, render_mode, NULL );
4653  if ( !error ||
4654  FT_ERR_NEQ( error, Cannot_Render_Glyph ) )
4655  break;
4656 
4657  /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
4658  /* is unsupported by the current renderer for this glyph image */
4659  /* format. */
4660 
4661  /* now, look for another renderer that supports the same */
4662  /* format. */
4663  renderer = FT_Lookup_Renderer( library, slot->format, &node );
4664  }
4665  }
4666  }
4667 
4668 #ifdef FT_DEBUG_LEVEL_TRACE
4669 
4670 #undef FT_COMPONENT
4671 #define FT_COMPONENT checksum
4672 
4673  /*
4674  * Computing the MD5 checksum is expensive, unnecessarily distorting a
4675  * possible profiling of FreeType if compiled with tracing support. For
4676  * this reason, we execute the following code only if explicitly
4677  * requested.
4678  */
4679 
4680  /* we use FT_TRACE3 in this block */
4681  if ( !error &&
4682  ft_trace_levels[trace_checksum] >= 3 &&
4683  slot->bitmap.buffer )
4684  {
4685  FT_Bitmap bitmap;
4686  FT_Error err;
4687 
4688 
4689  FT_Bitmap_Init( &bitmap );
4690 
4691  /* we convert to a single bitmap format for computing the checksum */
4692  /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
4693  err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 );
4694  if ( !err )
4695  {
4696  MD5_CTX ctx;
4697  unsigned char md5[16];
4698  unsigned long coverage = 0;
4699  int i, j;
4700  int rows = (int)bitmap.rows;
4701  int pitch = bitmap.pitch;
4702 
4703 
4704  FT_TRACE3(( "FT_Render_Glyph: bitmap %dx%d, %s (mode %d)\n",
4705  pitch,
4706  rows,
4707  pixel_modes[slot->bitmap.pixel_mode],
4708  slot->bitmap.pixel_mode ));
4709 
4710  for ( i = 0; i < rows; i++ )
4711  for ( j = 0; j < pitch; j++ )
4712  coverage += bitmap.buffer[i * pitch + j];
4713 
4714  FT_TRACE3(( " Total coverage: %lu\n", coverage ));
4715 
4716  MD5_Init( &ctx );
4717  if ( bitmap.buffer )
4718  MD5_Update( &ctx, bitmap.buffer,
4719  (unsigned long)rows * (unsigned long)pitch );
4720  MD5_Final( md5, &ctx );
4721 
4722  FT_TRACE3(( " MD5 checksum: " ));
4723  for ( i = 0; i < 16; i++ )
4724  FT_TRACE3(( "%02X", md5[i] ));
4725  FT_TRACE3(( "\n" ));
4726  }
4727 
4729  }
4730 
4731  /*
4732  * Dump bitmap in Netpbm format (PBM or PGM).
4733  */
4734 
4735  /* we use FT_TRACE7 in this block */
4736  if ( !error &&
4737  ft_trace_levels[trace_checksum] >= 7 )
4738  {
4739  if ( slot->bitmap.rows < 128U &&
4740  slot->bitmap.width < 128U &&
4741  slot->bitmap.buffer )
4742  {
4743  int rows = (int)slot->bitmap.rows;
4744  int width = (int)slot->bitmap.width;
4745  int pitch = slot->bitmap.pitch;
4746  int i, j, m;
4747 
4748  unsigned char* topleft = slot->bitmap.buffer;
4749 
4750 
4751  if ( pitch < 0 )
4752  topleft -= pitch * ( rows - 1 );
4753 
4754  FT_TRACE7(( "Netpbm image: start\n" ));
4755  switch ( slot->bitmap.pixel_mode )
4756  {
4757  case FT_PIXEL_MODE_MONO:
4758  FT_TRACE7(( "P1 %d %d\n", width, rows ));
4759  for ( i = 0; i < rows; i++ )
4760  {
4761  for ( j = 0; j < width; )
4762  for ( m = 128; m > 0 && j < width; m >>= 1, j++ )
4763  FT_TRACE7(( " %d",
4764  ( topleft[i * pitch + j / 8] & m ) != 0 ));
4765  FT_TRACE7(( "\n" ));
4766  }
4767  break;
4768 
4769  default:
4770  FT_TRACE7(( "P2 %d %d 255\n", width, rows ));
4771  for ( i = 0; i < rows; i++ )
4772  {
4773  for ( j = 0; j < width; j += 1 )
4774  FT_TRACE7(( " %3u", topleft[i * pitch + j] ));
4775  FT_TRACE7(( "\n" ));
4776  }
4777  }
4778  FT_TRACE7(( "Netpbm image: end\n" ));
4779  }
4780  else
4781  FT_TRACE7(( "Netpbm image: too large, omitted\n" ));
4782  }
4783 
4784 #undef FT_COMPONENT
4785 #define FT_COMPONENT objs
4786 
4787 #endif /* FT_DEBUG_LEVEL_TRACE */
4788 
4789  return error;
4790  }
4791 
4792 
4793  /* documentation is in freetype.h */
4794 
4797  FT_Render_Mode render_mode )
4798  {
4800 
4801 
4802  if ( !slot || !slot->face )
4803  return FT_THROW( Invalid_Argument );
4804 
4805  library = FT_FACE_LIBRARY( slot->face );
4806 
4807  return FT_Render_Glyph_Internal( library, slot, render_mode );
4808  }
4809 
4810 
4811  /*************************************************************************/
4812  /*************************************************************************/
4813  /*************************************************************************/
4814  /**** ****/
4815  /**** ****/
4816  /**** M O D U L E S ****/
4817  /**** ****/
4818  /**** ****/
4819  /*************************************************************************/
4820  /*************************************************************************/
4821  /*************************************************************************/
4822 
4823 
4824  /**************************************************************************
4825  *
4826  * @Function:
4827  * Destroy_Module
4828  *
4829  * @Description:
4830  * Destroys a given module object. For drivers, this also destroys
4831  * all child faces.
4832  *
4833  * @InOut:
4834  * module ::
4835  * A handle to the target driver object.
4836  *
4837  * @Note:
4838  * The driver _must_ be LOCKED!
4839  */
4840  static void
4842  {
4843  FT_Memory memory = module->memory;
4844  FT_Module_Class* clazz = module->clazz;
4845  FT_Library library = module->library;
4846 
4847 
4848  if ( library && library->auto_hinter == module )
4850 
4851  /* if the module is a renderer */
4852  if ( FT_MODULE_IS_RENDERER( module ) )
4854 
4855  /* if the module is a font driver, add some steps */
4856  if ( FT_MODULE_IS_DRIVER( module ) )
4858 
4859  /* finalize the module object */
4860  if ( clazz->module_done )
4861  clazz->module_done( module );
4862 
4863  /* discard it */
4864  FT_FREE( module );
4865  }
4866 
4867 
4868  /* documentation is in ftmodapi.h */
4869 
4872  const FT_Module_Class* clazz )
4873  {
4874  FT_Error error;
4875  FT_Memory memory;
4876  FT_Module module = NULL;
4877  FT_UInt nn;
4878 
4879 
4880 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
4881  FREETYPE_MINOR )
4882 
4883  if ( !library )
4884  return FT_THROW( Invalid_Library_Handle );
4885 
4886  if ( !clazz )
4887  return FT_THROW( Invalid_Argument );
4888 
4889  /* check FreeType version */
4890  if ( clazz->module_requires > FREETYPE_VER_FIXED )
4891  return FT_THROW( Invalid_Version );
4892 
4893  /* look for a module with the same name in the library's table */
4894  for ( nn = 0; nn < library->num_modules; nn++ )
4895  {
4896  module = library->modules[nn];
4897  if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
4898  {
4899  /* this installed module has the same name, compare their versions */
4900  if ( clazz->module_version <= module->clazz->module_version )
4901  return FT_THROW( Lower_Module_Version );
4902 
4903  /* remove the module from our list, then exit the loop to replace */
4904  /* it by our new version.. */
4906  break;
4907  }
4908  }
4909 
4910  memory = library->memory;
4911  error = FT_Err_Ok;
4912 
4914  {
4915  error = FT_THROW( Too_Many_Drivers );
4916  goto Exit;
4917  }
4918 
4919  /* allocate module object */
4920  if ( FT_ALLOC( module, clazz->module_size ) )
4921  goto Exit;
4922 
4923  /* base initialization */
4924  module->library = library;
4925  module->memory = memory;
4926  module->clazz = (FT_Module_Class*)clazz;
4927 
4928  /* check whether the module is a renderer - this must be performed */
4929  /* before the normal module initialization */
4930  if ( FT_MODULE_IS_RENDERER( module ) )
4931  {
4932  /* add to the renderers list */
4934  if ( error )
4935  goto Fail;
4936  }
4937 
4938  /* is the module a auto-hinter? */
4939  if ( FT_MODULE_IS_HINTER( module ) )
4941 
4942  /* if the module is a font driver */
4943  if ( FT_MODULE_IS_DRIVER( module ) )
4944  {
4945  FT_Driver driver = FT_DRIVER( module );
4946 
4947 
4948  driver->clazz = (FT_Driver_Class)module->clazz;
4949  }
4950 
4951  if ( clazz->module_init )
4952  {
4953  error = clazz->module_init( module );
4954  if ( error )
4955  goto Fail;
4956  }
4957 
4958  /* add module to the library's table */
4960 
4961  Exit:
4962  return error;
4963 
4964  Fail:
4965  if ( FT_MODULE_IS_RENDERER( module ) )
4966  {
4967  FT_Renderer renderer = FT_RENDERER( module );
4968 
4969 
4970  if ( renderer->clazz &&
4971  renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
4972  renderer->raster )
4973  renderer->clazz->raster_class->raster_done( renderer->raster );
4974  }
4975 
4976  FT_FREE( module );
4977  goto Exit;
4978  }
4979 
4980 
4981  /* documentation is in ftmodapi.h */
4982 
4985  const char* module_name )
4986  {
4987  FT_Module result = NULL;
4988  FT_Module* cur;
4989  FT_Module* limit;
4990 
4991 
4992  if ( !library || !module_name )
4993  return result;
4994 
4995  cur = library->modules;
4997 
4998  for ( ; cur < limit; cur++ )
4999  if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
5000  {
5001  result = cur[0];
5002  break;
5003  }
5004 
5005  return result;
5006  }
5007 
5008 
5009  /* documentation is in ftobjs.h */
5010 
5011  FT_BASE_DEF( const void* )
5013  const char* mod_name )
5014  {
5015  FT_Module module;
5016 
5017 
5018  /* test for valid `library' delayed to FT_Get_Module() */
5019 
5020  module = FT_Get_Module( library, mod_name );
5021 
5022  return module ? module->clazz->module_interface : 0;
5023  }
5024 
5025 
5028  const char* service_id,
5029  FT_Bool global )
5030  {