update for HEAD-2003050101
[reactos.git] / lib / freetype / src / pfr / pfrobjs.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  pfrobjs.c                                                              */
4 /*                                                                         */
5 /*    FreeType PFR object methods (body).                                  */
6 /*                                                                         */
7 /*  Copyright 2002 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 "pfrobjs.h"
20 #include "pfrload.h"
21 #include "pfrgload.h"
22 #include "pfrcmap.h"
23 #include "pfrsbit.h"
24 #include FT_OUTLINE_H
25 #include FT_INTERNAL_DEBUG_H
26
27 #include "pfrerror.h"
28
29 #undef  FT_COMPONENT
30 #define FT_COMPONENT  trace_pfr
31
32
33   /*************************************************************************/
34   /*************************************************************************/
35   /*****                                                               *****/
36   /*****                     FACE OBJECT METHODS                       *****/
37   /*****                                                               *****/
38   /*************************************************************************/
39   /*************************************************************************/
40
41   FT_LOCAL_DEF( void )
42   pfr_face_done( PFR_Face  face )
43   {
44     FT_Memory   memory = face->root.driver->root.memory;
45
46     /* we don't want dangling pointers */
47     face->root.family_name = NULL;
48     face->root.style_name  = NULL;
49     
50     /* finalize the physical font record */
51     pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
52
53     /* no need to finalize the logical font or the header */
54     FT_FREE( face->root.available_sizes );
55   }
56
57
58   FT_LOCAL_DEF( FT_Error )
59   pfr_face_init( FT_Stream      stream,
60                  PFR_Face       face,
61                  FT_Int         face_index,
62                  FT_Int         num_params,
63                  FT_Parameter*  params )
64   {
65     FT_Error  error;
66
67     FT_UNUSED( num_params );
68     FT_UNUSED( params );
69
70
71     /* load the header and check it */
72     error = pfr_header_load( &face->header, stream );
73     if ( error )
74       goto Exit;
75
76     if ( !pfr_header_check( &face->header ) )
77     {
78       FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
79       error = PFR_Err_Unknown_File_Format;
80       goto Exit;
81     }
82
83     /* check face index */
84     {
85       FT_UInt  num_faces;
86
87
88       error = pfr_log_font_count( stream,
89                                   face->header.log_dir_offset,
90                                   &num_faces );
91       if ( error )
92         goto Exit;
93
94       face->root.num_faces = num_faces;
95     }
96
97     if ( face_index < 0 )
98       goto Exit;
99
100     if ( face_index >= face->root.num_faces )
101     {
102       FT_ERROR(( "pfr_face_init: invalid face index\n" ));
103       error = PFR_Err_Invalid_Argument;
104       goto Exit;
105     }
106
107     /* load the face */
108     error = pfr_log_font_load(
109                &face->log_font, stream, face_index,
110                face->header.log_dir_offset,
111                FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
112     if ( error )
113       goto Exit;
114
115     /* now load the physical font descriptor */
116      error = pfr_phy_font_load( &face->phy_font, stream,
117                                  face->log_font.phys_offset,
118                                  face->log_font.phys_size );
119      if ( error )
120        goto Exit;
121
122      /* now, set-up all root face fields */
123      {
124        FT_Face      root     = FT_FACE( face );
125        PFR_PhyFont  phy_font = &face->phy_font;
126
127
128        root->face_index = face_index;
129        root->num_glyphs = phy_font->num_chars;
130        root->face_flags = FT_FACE_FLAG_SCALABLE;
131
132        if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
133          root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
134
135        if ( phy_font->flags & PFR_PHY_VERTICAL )
136          root->face_flags |= FT_FACE_FLAG_VERTICAL;
137        else
138          root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
139
140        if ( phy_font->num_strikes > 0 )
141          root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
142
143        if ( phy_font->num_kern_pairs > 0 )
144          root->face_flags |= FT_FACE_FLAG_KERNING;
145
146       /* if no family name was found in the "undocumented" auxiliary
147        * data, use the font ID instead. This sucks but is better than
148        * nothing
149        */
150        root->family_name = phy_font->family_name;
151        if ( root->family_name == NULL )
152          root->family_name = phy_font->font_id;
153
154       /* note that the style name can be NULL in certain PFR fonts,
155        * probably meaning "Regular"
156        */
157        root->style_name  = phy_font->style_name;
158
159        root->num_fixed_sizes = 0;
160        root->available_sizes = 0;
161
162        root->bbox         = phy_font->bbox;
163        root->units_per_EM = (FT_UShort)phy_font->outline_resolution;
164        root->ascender     = (FT_Short) phy_font->bbox.yMax;
165        root->descender    = (FT_Short) phy_font->bbox.yMin;
166        root->height       = (FT_Short)
167                               ( ( ( root->ascender - root->descender ) * 12 )
168                                 / 10 );
169
170        if ( phy_font->num_strikes > 0 )
171        {
172          FT_UInt          n, count = phy_font->num_strikes;
173          FT_Bitmap_Size*  size;
174          PFR_Strike       strike;
175          FT_Memory        memory = root->stream->memory;
176          
177          
178          if ( FT_NEW_ARRAY( root->available_sizes, count ) )
179            goto Exit;
180          
181          size   = root->available_sizes;
182          strike = phy_font->strikes;
183          for ( n = 0; n < count; n++, size++, strike++ )
184          {
185            size->height = (FT_UShort) strike->y_ppm;
186            size->width  = (FT_UShort) strike->x_ppm;
187          }
188          root->num_fixed_sizes = count;
189        }
190
191        /* now compute maximum advance width */
192        if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
193          root->max_advance_width = (FT_Short)phy_font->standard_advance;
194        else
195        {
196          FT_Int    max = 0;
197          FT_UInt   count = phy_font->num_chars;
198          PFR_Char  gchar = phy_font->chars;
199
200
201          for ( ; count > 0; count--, gchar++ )
202          {
203            if ( max < gchar->advance )
204              max = gchar->advance;
205          }
206
207          root->max_advance_width = (FT_Short)max;
208        }
209
210        root->max_advance_height = root->height;
211
212        root->underline_position  = (FT_Short)( - root->units_per_EM / 10 );
213        root->underline_thickness = (FT_Short)(   root->units_per_EM / 30 );
214
215        /* create charmap */
216        {
217          FT_CharMapRec  charmap;
218
219
220          charmap.face        = root;
221          charmap.platform_id = 3;
222          charmap.encoding_id = 1;
223          charmap.encoding    = FT_ENCODING_UNICODE;
224
225          FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
226
227 #if 0
228          /* Select default charmap */
229          if (root->num_charmaps)
230            root->charmap = root->charmaps[0];
231 #endif
232        }
233
234        /* check whether we've loaded any kerning pairs */
235        if ( phy_font->num_kern_pairs )
236          root->face_flags |= FT_FACE_FLAG_KERNING;
237      }
238
239   Exit:
240     return error;
241   }
242
243
244   /*************************************************************************/
245   /*************************************************************************/
246   /*****                                                               *****/
247   /*****                    SLOT OBJECT METHOD                         *****/
248   /*****                                                               *****/
249   /*************************************************************************/
250   /*************************************************************************/
251
252   FT_LOCAL_DEF( FT_Error )
253   pfr_slot_init( PFR_Slot  slot )
254   {
255     FT_GlyphLoader  loader = slot->root.internal->loader;
256
257     pfr_glyph_init( &slot->glyph, loader );
258
259     return 0;
260   }
261
262
263   FT_LOCAL_DEF( void )
264   pfr_slot_done( PFR_Slot  slot )
265   {
266     pfr_glyph_done( &slot->glyph );
267   }
268
269
270   FT_LOCAL_DEF( FT_Error )
271   pfr_slot_load( PFR_Slot  slot,
272                  PFR_Size  size,
273                  FT_UInt   gindex,
274                  FT_Int32  load_flags )
275   {
276     FT_Error     error;
277     PFR_Face     face    = (PFR_Face)slot->root.face;
278     PFR_Char     gchar;
279     FT_Outline*  outline = &slot->root.outline;
280     FT_ULong     gps_offset;
281
282     if (gindex > 0)
283       gindex--;
284
285     /* check that the glyph index is correct */
286     FT_ASSERT( gindex < face->phy_font.num_chars );
287
288     /* try to load an embedded bitmap */
289     if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
290     {
291       error = pfr_slot_load_bitmap( slot, size, gindex );
292       if ( error == 0 )
293         goto Exit;
294     }
295
296     if ( load_flags & FT_LOAD_SBITS_ONLY )
297     {
298       error = FT_Err_Invalid_Argument;
299       goto Exit;
300     }
301
302     gchar               = face->phy_font.chars + gindex;
303     slot->root.format   = FT_GLYPH_FORMAT_OUTLINE;
304     outline->n_points   = 0;
305     outline->n_contours = 0;
306     gps_offset          = face->header.gps_section_offset;
307
308     /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
309     error = pfr_glyph_load( &slot->glyph, face->root.stream,
310                             gps_offset, gchar->gps_offset, gchar->gps_size );
311
312     if ( !error )
313     {
314       FT_BBox            cbox;
315       FT_Glyph_Metrics*  metrics = &slot->root.metrics;
316       FT_Pos             advance;
317       FT_Int             em_metrics, em_outline;
318       FT_Bool            scaling;
319
320
321       scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
322
323       /* copy outline data */
324       *outline = slot->glyph.loader->base.outline;
325
326       outline->flags &= ~FT_OUTLINE_OWNER;
327       outline->flags |= FT_OUTLINE_REVERSE_FILL;
328
329       if ( size && size->root.metrics.y_ppem < 24 )
330         outline->flags |= FT_OUTLINE_HIGH_PRECISION;
331
332       /* compute the advance vector */
333       metrics->horiAdvance = 0;
334       metrics->vertAdvance = 0;
335
336       advance    = gchar->advance;
337       em_metrics = face->phy_font.metrics_resolution;
338       em_outline = face->phy_font.outline_resolution;
339
340       if ( em_metrics != em_outline )
341         advance = FT_MulDiv( advance, em_outline, em_metrics );
342
343       if ( face->phy_font.flags & PFR_PHY_VERTICAL )
344         metrics->vertAdvance = advance;
345       else
346         metrics->horiAdvance = advance;
347
348       slot->root.linearHoriAdvance = metrics->horiAdvance;
349       slot->root.linearVertAdvance = metrics->vertAdvance;
350
351       /* make-up vertical metrics(?) */
352       metrics->vertBearingX = 0;
353       metrics->vertBearingY = 0;
354
355       /* scale when needed */
356       if ( scaling )
357       {
358         FT_Int      n;
359         FT_Fixed    x_scale = size->root.metrics.x_scale;
360         FT_Fixed    y_scale = size->root.metrics.y_scale;
361         FT_Vector*  vec     = outline->points;
362
363
364         /* scale outline points */
365         for ( n = 0; n < outline->n_points; n++, vec++ )
366         {
367           vec->x = FT_MulFix( vec->x, x_scale );
368           vec->y = FT_MulFix( vec->y, y_scale );
369         }
370
371         /* scale the advance */
372         metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
373         metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
374       }
375
376       /* compute the rest of the metrics */
377       FT_Outline_Get_CBox( outline, &cbox );
378
379       metrics->width        = cbox.xMax - cbox.xMin;
380       metrics->height       = cbox.yMax - cbox.yMin;
381       metrics->horiBearingX = cbox.xMin;
382       metrics->horiBearingY = cbox.yMax - metrics->height;
383     }
384
385   Exit:
386     return error;
387   }
388
389
390   /*************************************************************************/
391   /*************************************************************************/
392   /*****                                                               *****/
393   /*****                      KERNING METHOD                           *****/
394   /*****                                                               *****/
395   /*************************************************************************/
396   /*************************************************************************/
397
398   FT_LOCAL_DEF( FT_Error )
399   pfr_face_get_kerning( PFR_Face    face,
400                         FT_UInt     glyph1,
401                         FT_UInt     glyph2,
402                         FT_Vector*  kerning )
403   {
404     FT_Error      error;
405     PFR_PhyFont   phy_font = &face->phy_font;
406     PFR_KernItem  item     = phy_font->kern_items;
407     FT_UInt32     idx      = PFR_KERN_INDEX( glyph1, glyph2 );
408
409
410     kerning->x = 0;
411     kerning->y = 0;
412
413     /* find the kerning item containing our pair */
414     while ( item )
415     {
416       if ( item->pair1 <= idx && idx <= item->pair2 )
417         goto Found_Item;
418
419       item = item->next;
420     }
421
422     /* not found */
423     goto Exit;
424
425   Found_Item:
426     {
427       /* perform simply binary search within the item */
428       FT_UInt    min, mid, max;
429       FT_Stream  stream = face->root.stream;
430       FT_Byte*   p;
431
432
433       if ( FT_STREAM_SEEK( item->offset )                       ||
434            FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
435         goto Exit;
436
437       min = 0;
438       max = item->pair_count;
439       while ( min < max )
440       {
441         FT_UInt  char1, char2, charcode;
442
443
444         mid = ( min + max ) >> 1;
445         p   = stream->cursor + mid*item->pair_size;
446
447         if ( item->flags & PFR_KERN_2BYTE_CHAR )
448         {
449           char1 = FT_NEXT_USHORT( p );
450           char2 = FT_NEXT_USHORT( p );
451         }
452         else
453         {
454           char1 = FT_NEXT_USHORT( p );
455           char2 = FT_NEXT_USHORT( p );
456         }
457         charcode = PFR_KERN_INDEX( char1, char2 );
458
459         if ( idx == charcode )
460         {
461           if ( item->flags & PFR_KERN_2BYTE_ADJ )
462             kerning->x = item->base_adj + FT_NEXT_SHORT( p );
463           else
464             kerning->x = item->base_adj + FT_NEXT_CHAR( p );
465
466           break;
467         }
468         if ( idx > charcode )
469           min = mid + 1;
470         else
471           max = mid;
472       }
473
474       FT_FRAME_EXIT();
475     }
476
477   Exit:
478     return 0;
479   }
480
481 /* END */