update for HEAD-2003021201
[reactos.git] / subsys / win32k / freetype / src / cff / t2load.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  t2load.c                                                               */
4 /*                                                                         */
5 /*    TrueType glyph data/program tables loader (body).                    */
6 /*                                                                         */
7 /*  Copyright 1996-2000 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/internal/ftdebug.h>
20 #include <freetype/internal/ftobjs.h>
21 #include <freetype/internal/ftstream.h>
22 #include <freetype/internal/psnames.h>
23
24 #include <freetype/internal/t2errors.h>
25 #include <freetype/tttags.h>
26
27
28 #ifdef FT_FLAT_COMPILE
29
30 #include "t2load.h"
31 #include "t2parse.h"
32
33 #else
34
35 #include <freetype/src/cff/t2load.h>
36 #include <freetype/src/cff/t2parse.h>
37
38 #endif
39
40
41   /*************************************************************************/
42   /*                                                                       */
43   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
44   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
45   /* messages during execution.                                            */
46   /*                                                                       */
47 #undef  FT_COMPONENT
48 #define FT_COMPONENT  trace_t2load
49
50
51  /* read a CFF offset from memory */
52   static
53   FT_ULong  t2_get_offset( FT_Byte*  p,
54                            FT_Byte   off_size )
55   {
56     FT_ULong  result;
57
58
59     for ( result = 0; off_size > 0; off_size-- )
60     {
61       result <<= 8;
62       result  |= *p++;
63     }
64
65     return result;
66   }
67
68
69   static
70   FT_Error  t2_new_cff_index( CFF_Index*  index,
71                               FT_Stream   stream,
72                               FT_Bool     load )
73   {
74     FT_Error  error;
75     FT_Memory memory = stream->memory;
76     FT_UShort count;
77
78
79     MEM_Set( index, 0, sizeof ( *index ) );
80
81     index->stream = stream;
82     if ( !READ_UShort( count ) &&
83          count > 0             )
84     {
85       FT_Byte*   p;
86       FT_Byte    offsize;
87       FT_ULong   data_size;
88       FT_ULong*  poff;
89
90
91       /* there is at least one element; read the offset size,           */
92       /* then access the offset table to compute the index's total size */
93       if ( READ_Byte( offsize ) )
94         goto Exit;
95
96       index->stream   = stream;
97       index->count    = count;
98       index->off_size = offsize;
99       data_size       = (FT_ULong)( count + 1 ) * offsize;
100
101       if ( ALLOC_ARRAY( index->offsets, count + 1, FT_ULong ) ||
102            ACCESS_Frame( data_size )                          )
103         goto Exit;
104
105       poff = index->offsets;
106       p    = (FT_Byte*)stream->cursor;
107
108       for ( ; (FT_Short)count >= 0; count-- )
109       {
110         poff[0] = t2_get_offset( p, offsize );
111         poff++;
112         p += offsize;
113       }
114
115       FORGET_Frame();
116
117       index->data_offset = FILE_Pos();
118       data_size          = poff[-1] - 1;
119
120       if ( load )
121       {
122         /* load the data */
123         if ( EXTRACT_Frame( data_size, index->bytes ) )
124           goto Exit;
125       }
126       else
127       {
128         /* skip the data */
129         (void)FILE_Skip( data_size );
130       }
131     }
132
133   Exit:
134     if ( error )
135       FREE( index->offsets );
136
137     return error;
138   }
139
140
141   static
142   void  t2_done_cff_index( CFF_Index*  index )
143   {
144     if ( index->stream )
145     {
146       FT_Stream  stream = index->stream;
147       FT_Memory  memory = stream->memory;
148
149
150       if ( index->bytes )
151         RELEASE_Frame( index->bytes );
152
153       FREE( index->offsets );
154       MEM_Set( index, 0, sizeof ( *index ) );
155     }
156   }
157
158
159   static
160   FT_Error  t2_explicit_cff_index( CFF_Index*  index,
161                                    FT_Byte***  table )
162   {
163     FT_Error   error  = 0;
164     FT_Memory  memory = index->stream->memory;
165     FT_UInt    n, offset, old_offset;
166     FT_Byte**  t;
167
168
169     *table = 0;
170
171     if ( index->count > 0 && !ALLOC_ARRAY( t, index->count + 1, FT_Byte* ) )
172     {
173       old_offset = 1;
174       for ( n = 0; n <= index->count; n++ )
175       {
176         offset = index->offsets[n];
177         if ( !offset )
178           offset = old_offset;
179
180         t[n] = index->bytes + offset - 1;
181
182         old_offset = offset;
183       }
184       *table = t;
185     }
186
187     return error;
188   }
189
190
191   LOCAL_FUNC
192   FT_Error  T2_Access_Element( CFF_Index*  index,
193                                FT_UInt     element,
194                                FT_Byte**   pbytes,
195                                FT_ULong*   pbyte_len )
196   {
197     FT_Error  error = 0;
198
199
200     if ( index && index->count > element )
201     {
202       /* compute start and end offsets */
203       FT_ULong  off1, off2;
204
205
206       off1 = index->offsets[element];
207       if ( off1 )
208       {
209         do
210         {
211           element++;
212           off2 = index->offsets[element];
213
214         } while ( off2 == 0 && element < index->count );
215
216         if ( !off2 )
217           off1 = 0;
218       }
219
220       /* access element */
221       if ( off1 )
222       {
223         *pbyte_len = off2 - off1;
224
225         if ( index->bytes )
226         {
227           /* this index was completely loaded in memory, that's easy */
228           *pbytes = index->bytes + off1 - 1;
229         }
230         else
231         {
232           /* this index is still on disk/file, access it through a frame */
233           FT_Stream  stream = index->stream;
234
235
236           if ( FILE_Seek( index->data_offset + off1 - 1 ) ||
237                EXTRACT_Frame( off2 - off1, *pbytes )      )
238             goto Exit;
239         }
240       }
241       else
242       {
243         /* empty index element */
244         *pbytes    = 0;
245         *pbyte_len = 0;
246       }
247     }
248     else
249       error = T2_Err_Invalid_Argument;
250
251   Exit:
252     return error;
253   }
254
255
256   LOCAL_FUNC
257   void  T2_Forget_Element( CFF_Index*  index,
258                            FT_Byte**   pbytes )
259   {
260     if ( index->bytes == 0 )
261     {
262       FT_Stream  stream = index->stream;
263
264
265       RELEASE_Frame( *pbytes );
266     }
267   }
268
269
270   LOCAL_FUNC
271   FT_String*  T2_Get_Name( CFF_Index*  index,
272                            FT_UInt     element )
273   {
274     FT_Memory   memory = index->stream->memory;
275     FT_Byte*    bytes;
276     FT_ULong    byte_len;
277     FT_Error    error;
278     FT_String*  name = 0;
279
280
281     error = T2_Access_Element( index, element, &bytes, &byte_len );
282     if ( error )
283       goto Exit;
284
285     if ( !ALLOC( name, byte_len + 1 ) )
286     {
287       MEM_Copy( name, bytes, byte_len );
288       name[byte_len] = 0;
289     }
290     T2_Forget_Element( index, &bytes );
291
292   Exit:
293     return name;
294   }
295
296
297   LOCAL_FUNC
298   FT_String*  T2_Get_String( CFF_Index*          index,
299                              FT_UInt             sid,
300                              PSNames_Interface*  interface )
301   {
302     /* if it is not a standard string, return it */
303     if ( sid > 390 )
304       return T2_Get_Name( index, sid - 390 );
305
306     /* that's a standard string, fetch a copy from the PSName module */
307     {
308       FT_String*   name       = 0;
309       const char*  adobe_name = interface->adobe_std_strings( sid );
310       FT_UInt      len;
311
312
313       if ( adobe_name )
314       {
315         FT_Memory memory = index->stream->memory;
316         FT_Error  error;
317
318
319         len = (FT_UInt)strlen( adobe_name );
320         if ( !ALLOC( name, len + 1 ) )
321         {
322           MEM_Copy( name, adobe_name, len );
323           name[len] = 0;
324         }
325       }
326
327       return name;
328     }
329   }
330
331
332   /*************************************************************************/
333   /*************************************************************************/
334   /***                                                                   ***/
335   /***   FD Select table support                                         ***/
336   /***                                                                   ***/
337   /*************************************************************************/
338   /*************************************************************************/
339
340
341   static
342   void  CFF_Done_FD_Select( CFF_FD_Select*  select,
343                             FT_Stream       stream )
344   {
345     if ( select->data )
346       RELEASE_Frame( select->data );
347
348     select->data_size   = 0;
349     select->format      = 0;
350     select->range_count = 0;
351   }
352
353
354   static
355   FT_Error  CFF_Load_FD_Select( CFF_FD_Select*  select,
356                                 FT_UInt         num_glyphs,
357                                 FT_Stream       stream,
358                                 FT_ULong        offset )
359   {
360     FT_Error       error;
361     FT_Byte        format;
362     FT_UInt        num_ranges;
363
364
365     /* read format */
366     if ( FILE_Seek( offset ) || READ_Byte( format ) )
367       goto Exit;
368
369     select->format      = format;
370     select->cache_count = 0;   /* clear cache */
371
372     switch ( format )
373     {
374     case 0:     /* format 0, that's simple */
375       select->data_size = num_glyphs;
376       goto Load_Data;
377
378     case 3:     /* format 3, a tad more complex */
379       if ( READ_UShort( num_ranges ) )
380         goto Exit;
381
382       select->data_size = num_ranges * 3 + 2;
383
384     Load_Data:
385       if ( EXTRACT_Frame( select->data_size, select->data ) )
386         goto Exit;
387       break;
388
389     default:    /* hmm... that's wrong */
390       error = T2_Err_Invalid_File_Format;
391     }
392
393   Exit:
394     return error;
395   }
396
397
398   LOCAL_FUNC
399   FT_Byte  CFF_Get_FD( CFF_FD_Select*  select,
400                        FT_UInt         glyph_index )
401   {
402     FT_Byte  fd = 0;
403
404
405     switch ( select->format )
406     {
407     case 0:
408       fd = select->data[glyph_index];
409       break;
410
411     case 3:
412       /* first, compare to cache */
413       if ( (FT_UInt)(glyph_index-select->cache_first) < select->cache_count )
414       {
415         fd = select->cache_fd;
416         break;
417       }
418
419       /* then, lookup the ranges array */
420       {
421         FT_Byte*  p       = select->data;
422         FT_Byte*  p_limit = p + select->data_size;
423         FT_Byte   fd2;
424         FT_UInt   first, limit;
425
426
427         first = NEXT_UShort( p );
428         do
429         {
430           if ( glyph_index < first )
431             break;
432
433           fd2   = *p++;
434           limit = NEXT_UShort( p );
435
436           if ( glyph_index < limit )
437           {
438             fd = fd2;
439
440             /* update cache */
441             select->cache_first = first;
442             select->cache_count = limit-first;
443             select->cache_fd    = fd2;
444             break;
445           }
446           first = limit;
447
448         } while ( p < p_limit );
449       }
450       break;
451
452     default:
453       ;
454     }
455
456     return fd;
457   }
458
459
460   /*************************************************************************/
461   /*************************************************************************/
462   /***                                                                   ***/
463   /***   CFF font support                                                ***/
464   /***                                                                   ***/
465   /*************************************************************************/
466   /*************************************************************************/
467
468
469   static
470   FT_Error  CFF_Load_SubFont( CFF_SubFont*  font,
471                               CFF_Index*    index,
472                               FT_UInt       font_index,
473                               FT_Stream     stream,
474                               FT_ULong      base_offset )
475   {
476     FT_Error        error;
477     T2_Parser       parser;
478     FT_Byte*        dict;
479     FT_ULong        dict_len;
480     CFF_Font_Dict*  top  = &font->font_dict;
481     CFF_Private*    priv = &font->private_dict;
482
483
484     T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->font_dict );
485
486     /* set defaults */
487     MEM_Set( top, 0, sizeof ( *top ) );
488
489     top->underline_position  = -100;
490     top->underline_thickness = 50;
491     top->charstring_type     = 2;
492     top->font_matrix.xx      = 0x10000L;
493     top->font_matrix.yy      = 0x10000L;
494     top->cid_count           = 8720;
495
496     error = T2_Access_Element( index, font_index, &dict, &dict_len ) ||
497             T2_Parser_Run( &parser, dict, dict + dict_len );
498
499     T2_Forget_Element( index, &dict );
500
501     if ( error )
502       goto Exit;
503
504     /* if it is a CID font, we stop there */
505     if ( top->cid_registry )
506       goto Exit;
507
508     /* parse the private dictionary, if any */
509     if ( top->private_offset && top->private_size )
510     {
511       /* set defaults */
512       MEM_Set( priv, 0, sizeof ( *priv ) );
513
514       priv->blue_shift       = 7;
515       priv->blue_fuzz        = 1;
516       priv->lenIV            = -1;
517       priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L;
518       priv->blue_scale       = (FT_Fixed)0.039625 * 0x10000L;
519
520       T2_Parser_Init( &parser, T2CODE_PRIVATE, priv );
521
522       if ( FILE_Seek( base_offset + font->font_dict.private_offset ) ||
523            ACCESS_Frame( font->font_dict.private_size )              )
524         goto Exit;
525
526       error = T2_Parser_Run( &parser,
527                              (FT_Byte*)stream->cursor,
528                              (FT_Byte*)stream->limit );
529       FORGET_Frame();
530       if ( error )
531         goto Exit;
532     }
533
534     /* read the local subrs, if any */
535     if ( priv->local_subrs_offset )
536     {
537       if ( FILE_Seek( base_offset + top->private_offset +
538                       priv->local_subrs_offset ) )
539         goto Exit;
540
541       error = t2_new_cff_index( &font->local_subrs_index, stream, 1 );
542       if ( error )
543         goto Exit;
544
545       font->num_local_subrs = font->local_subrs_index.count;
546       error = t2_explicit_cff_index( &font->local_subrs_index,
547                                      &font->local_subrs );
548     }
549
550   Exit:
551     return error;
552   }
553
554
555   static
556   void  CFF_Done_SubFont( FT_Memory     memory,
557                           CFF_SubFont*  subfont )
558   {
559     if ( subfont )
560     {
561       t2_done_cff_index( &subfont->local_subrs_index );
562       FREE( subfont->local_subrs );
563     }
564   }
565
566
567   LOCAL_FUNC
568   FT_Error  T2_Load_CFF_Font( FT_Stream  stream,
569                               FT_Int     face_index,
570                               CFF_Font*  font )
571   {
572     static const FT_Frame_Field  cff_header_fields[] =
573     {
574       FT_FRAME_START( 4 ),
575         FT_FRAME_BYTE( CFF_Font, version_major ),
576         FT_FRAME_BYTE( CFF_Font, version_minor ),
577         FT_FRAME_BYTE( CFF_Font, header_size ),
578         FT_FRAME_BYTE( CFF_Font, absolute_offsize ),
579       FT_FRAME_END
580     };
581
582     FT_Error        error;
583     FT_Memory       memory = stream->memory;
584     FT_ULong        base_offset;
585     CFF_Font_Dict*  dict;
586
587
588     MEM_Set( font, 0, sizeof ( *font ) );
589     font->stream = stream;
590     font->memory = memory;
591     dict         = &font->top_font.font_dict;
592     base_offset  = FILE_Pos();
593
594     /* read CFF font header */
595     if ( READ_Fields( cff_header_fields, font ) )
596       goto Exit;
597
598     /* check format */
599     if ( font->version_major   != 1 ||
600          font->header_size      < 4 ||
601          font->absolute_offsize > 4 )
602     {
603       FT_TRACE2(( "[not a CFF font header!]\n" ));
604       error = FT_Err_Unknown_File_Format;
605       goto Exit;
606     }
607
608     /* skip the rest of the header */
609     (void)FILE_Skip( font->header_size - 4 );
610
611     /* read the name, top dict, string and global subrs index */
612     error = t2_new_cff_index( &font->name_index, stream, 0 )       ||
613             t2_new_cff_index( &font->font_dict_index, stream, 0 )  ||
614             t2_new_cff_index( &font->string_index, stream, 0 )     ||
615             t2_new_cff_index( &font->global_subrs_index, stream, 1 );
616     if ( error )
617       goto Exit;
618
619     /* well, we don't really forget the `disabled' fonts... */
620     font->num_faces = font->name_index.count;
621     if ( face_index >= (FT_Int)font->num_faces )
622     {
623       FT_ERROR(( "T2_Load_CFF_Font: incorrect face index = %d\n",
624                  face_index ));
625       error = T2_Err_Invalid_Argument;
626     }
627
628     /* in case of a font format check, simply exit now */
629     if ( face_index < 0 )
630       goto Exit;
631
632     /* now, parse the top-level font dictionary */
633     error = CFF_Load_SubFont( &font->top_font,
634                               &font->font_dict_index,
635                               face_index,
636                               stream,
637                               base_offset );
638     if ( error )
639       goto Exit;
640
641     /* now, check for a CID font */
642     if ( dict->cid_registry )
643     {
644       CFF_Index     fd_index;
645       CFF_SubFont*  sub;
646       FT_UInt       index;
647
648
649       /* this is a CID-keyed font, we must now allocate a table of */
650       /* sub-fonts, then load each of them separately              */
651       if ( FILE_Seek( base_offset + dict->cid_fd_array_offset ) )
652         goto Exit;
653
654       error = t2_new_cff_index( &fd_index, stream, 0 );
655       if ( error )
656         goto Exit;
657
658       if ( fd_index.count > CFF_MAX_CID_FONTS )
659       {
660         FT_ERROR(( "T2_Load_CFF_Font: FD array too large in CID font\n" ));
661         goto Fail_CID;
662       }
663
664       /* allocate & read each font dict independently */
665       font->num_subfonts = fd_index.count;
666       if ( ALLOC_ARRAY( sub, fd_index.count, CFF_SubFont ) )
667         goto Fail_CID;
668
669       /* setup pointer table */
670       for ( index = 0; index < fd_index.count; index++ )
671         font->subfonts[index] = sub + index;
672
673       /* now load each sub font independently */
674       for ( index = 0; index < fd_index.count; index++ )
675       {
676         sub = font->subfonts[index];
677         error = CFF_Load_SubFont( sub, &fd_index, index,
678                                   stream, base_offset );
679         if ( error )
680           goto Fail_CID;
681       }
682
683       /* now load the FD Select array */
684       error = CFF_Load_FD_Select( &font->fd_select,
685                                   dict->cid_count,
686                                   stream,
687                                   base_offset + dict->cid_fd_select_offset );
688
689    Fail_CID:
690       t2_done_cff_index( &fd_index );
691
692       if ( error )
693         goto Exit;
694     }
695     else
696       font->num_subfonts = 0;
697
698     /* read the charstrings index now */
699     if ( dict->charstrings_offset == 0 )
700     {
701       FT_ERROR(( "T2_Load_CFF_Font: no charstrings offset!\n" ));
702       error = FT_Err_Unknown_File_Format;
703       goto Exit;
704     }
705
706     if ( FILE_Seek( base_offset + dict->charstrings_offset ) )
707       goto Exit;
708
709     error = t2_new_cff_index( &font->charstrings_index, stream, 0 );
710     if ( error )
711       goto Exit;
712
713     /* explicit the global subrs */
714     font->num_global_subrs = font->global_subrs_index.count;
715     font->num_glyphs       = font->charstrings_index.count;
716
717     error = t2_explicit_cff_index( &font->global_subrs_index,
718                                    &font->global_subrs ) ;
719
720     if ( error )
721       goto Exit;
722
723     /* get the font name */
724     font->font_name = T2_Get_Name( &font->name_index, face_index );
725
726   Exit:
727     return error;
728   }
729
730
731   LOCAL_FUNC
732   void  T2_Done_CFF_Font( CFF_Font*  font )
733   {
734     FT_Memory  memory = font->memory;
735     FT_UInt    index;
736
737
738     t2_done_cff_index( &font->global_subrs_index );
739     t2_done_cff_index( &font->string_index );
740     t2_done_cff_index( &font->font_dict_index );
741     t2_done_cff_index( &font->name_index );
742     t2_done_cff_index( &font->charstrings_index );
743
744     /* release font dictionaries */
745     for ( index = 0; index < font->num_subfonts; index++ )
746       CFF_Done_SubFont( memory, font->subfonts[index] );
747
748     CFF_Done_SubFont( memory, &font->top_font );
749
750     CFF_Done_FD_Select( &font->fd_select, font->stream );
751
752     FREE( font->global_subrs );
753     FREE( font->font_name );
754   }
755
756
757 /* END */