1 /***************************************************************************/
2 /*                                                                         */
3 /*  pfrobjs.c                                                              */
4 /*                                                                         */
5 /*    FreeType PFR object methods (body).                                  */
6 /*                                                                         */
7 /*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 )
pfr_face_done(FT_Face pfrface)42   pfr_face_done( FT_Face  pfrface )     /* PFR_Face */
43   {
44     PFR_Face   face = (PFR_Face)pfrface;
45     FT_Memory  memory;
46 
47 
48     if ( !face )
49       return;
50 
51     memory = pfrface->driver->root.memory;
52 
53     /* we don't want dangling pointers */
54     pfrface->family_name = NULL;
55     pfrface->style_name  = NULL;
56 
57     /* finalize the physical font record */
58     pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
59 
60     /* no need to finalize the logical font or the header */
61     FT_FREE( pfrface->available_sizes );
62   }
63 
64 
65   FT_LOCAL_DEF( FT_Error )
pfr_face_init(FT_Stream stream,FT_Face pfrface,FT_Int face_index,FT_Int num_params,FT_Parameter * params)66   pfr_face_init( FT_Stream      stream,
67                  FT_Face        pfrface,
68                  FT_Int         face_index,
69                  FT_Int         num_params,
70                  FT_Parameter*  params )
71   {
72     PFR_Face  face = (PFR_Face)pfrface;
73     FT_Error  error;
74 
75     FT_UNUSED( num_params );
76     FT_UNUSED( params );
77 
78 
79     /* load the header and check it */
80     error = pfr_header_load( &face->header, stream );
81     if ( error )
82       goto Exit;
83 
84     if ( !pfr_header_check( &face->header ) )
85     {
86       FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
87       error = PFR_Err_Unknown_File_Format;
88       goto Exit;
89     }
90 
91     /* check face index */
92     {
93       FT_UInt  num_faces;
94 
95 
96       error = pfr_log_font_count( stream,
97                                   face->header.log_dir_offset,
98                                   &num_faces );
99       if ( error )
100         goto Exit;
101 
102       pfrface->num_faces = num_faces;
103     }
104 
105     if ( face_index < 0 )
106       goto Exit;
107 
108     if ( face_index >= pfrface->num_faces )
109     {
110       FT_ERROR(( "pfr_face_init: invalid face index\n" ));
111       error = PFR_Err_Invalid_Argument;
112       goto Exit;
113     }
114 
115     /* load the face */
116     error = pfr_log_font_load(
117                &face->log_font, stream, face_index,
118                face->header.log_dir_offset,
119                FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
120     if ( error )
121       goto Exit;
122 
123     /* now load the physical font descriptor */
124     error = pfr_phy_font_load( &face->phy_font, stream,
125                                face->log_font.phys_offset,
126                                face->log_font.phys_size );
127     if ( error )
128       goto Exit;
129 
130     /* now set up all root face fields */
131     {
132       PFR_PhyFont  phy_font = &face->phy_font;
133 
134 
135       pfrface->face_index = face_index;
136       pfrface->num_glyphs = phy_font->num_chars + 1;
137       pfrface->face_flags = FT_FACE_FLAG_SCALABLE;
138 
139       /* if all characters point to the same gps_offset 0, we */
140       /* assume that the font only contains bitmaps           */
141       {
142         FT_UInt  nn;
143 
144 
145         for ( nn = 0; nn < phy_font->num_chars; nn++ )
146           if ( phy_font->chars[nn].gps_offset != 0 )
147             break;
148 
149         if ( nn == phy_font->num_chars )
150           pfrface->face_flags = 0;        /* not scalable */
151       }
152 
153       if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
154         pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
155 
156       if ( phy_font->flags & PFR_PHY_VERTICAL )
157         pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
158       else
159         pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
160 
161       if ( phy_font->num_strikes > 0 )
162         pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
163 
164       if ( phy_font->num_kern_pairs > 0 )
165         pfrface->face_flags |= FT_FACE_FLAG_KERNING;
166 
167       /* If no family name was found in the "undocumented" auxiliary
168        * data, use the font ID instead.  This sucks but is better than
169        * nothing.
170        */
171       pfrface->family_name = phy_font->family_name;
172       if ( pfrface->family_name == NULL )
173         pfrface->family_name = phy_font->font_id;
174 
175       /* note that the style name can be NULL in certain PFR fonts,
176        * probably meaning "Regular"
177        */
178       pfrface->style_name = phy_font->style_name;
179 
180       pfrface->num_fixed_sizes = 0;
181       pfrface->available_sizes = 0;
182 
183       pfrface->bbox         = phy_font->bbox;
184       pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
185       pfrface->ascender     = (FT_Short) phy_font->bbox.yMax;
186       pfrface->descender    = (FT_Short) phy_font->bbox.yMin;
187 
188       pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
189       if ( pfrface->height < pfrface->ascender - pfrface->descender )
190         pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender);
191 
192       if ( phy_font->num_strikes > 0 )
193       {
194         FT_UInt          n, count = phy_font->num_strikes;
195         FT_Bitmap_Size*  size;
196         PFR_Strike       strike;
197         FT_Memory        memory = pfrface->stream->memory;
198 
199 
200         if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) )
201           goto Exit;
202 
203         size   = pfrface->available_sizes;
204         strike = phy_font->strikes;
205         for ( n = 0; n < count; n++, size++, strike++ )
206         {
207           size->height = (FT_UShort)strike->y_ppm;
208           size->width  = (FT_UShort)strike->x_ppm;
209           size->size   = strike->y_ppm << 6;
210           size->x_ppem = strike->x_ppm << 6;
211           size->y_ppem = strike->y_ppm << 6;
212         }
213         pfrface->num_fixed_sizes = count;
214       }
215 
216       /* now compute maximum advance width */
217       if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
218         pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
219       else
220       {
221         FT_Int    max = 0;
222         FT_UInt   count = phy_font->num_chars;
223         PFR_Char  gchar = phy_font->chars;
224 
225 
226         for ( ; count > 0; count--, gchar++ )
227         {
228           if ( max < gchar->advance )
229             max = gchar->advance;
230         }
231 
232         pfrface->max_advance_width = (FT_Short)max;
233       }
234 
235       pfrface->max_advance_height = pfrface->height;
236 
237       pfrface->underline_position  = (FT_Short)( -pfrface->units_per_EM / 10 );
238       pfrface->underline_thickness = (FT_Short)(  pfrface->units_per_EM / 30 );
239 
240       /* create charmap */
241       {
242         FT_CharMapRec  charmap;
243 
244 
245         charmap.face        = pfrface;
246         charmap.platform_id = 3;
247         charmap.encoding_id = 1;
248         charmap.encoding    = FT_ENCODING_UNICODE;
249 
250         FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
251 
252 #if 0
253         /* Select default charmap */
254         if ( pfrface->num_charmaps )
255           pfrface->charmap = pfrface->charmaps[0];
256 #endif
257       }
258 
259       /* check whether we've loaded any kerning pairs */
260       if ( phy_font->num_kern_pairs )
261         pfrface->face_flags |= FT_FACE_FLAG_KERNING;
262     }
263 
264   Exit:
265     return error;
266   }
267 
268 
269   /*************************************************************************/
270   /*************************************************************************/
271   /*****                                                               *****/
272   /*****                    SLOT OBJECT METHOD                         *****/
273   /*****                                                               *****/
274   /*************************************************************************/
275   /*************************************************************************/
276 
277   FT_LOCAL_DEF( FT_Error )
pfr_slot_init(FT_GlyphSlot pfrslot)278   pfr_slot_init( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
279   {
280     PFR_Slot        slot   = (PFR_Slot)pfrslot;
281     FT_GlyphLoader  loader = pfrslot->internal->loader;
282 
283 
284     pfr_glyph_init( &slot->glyph, loader );
285 
286     return 0;
287   }
288 
289 
290   FT_LOCAL_DEF( void )
pfr_slot_done(FT_GlyphSlot pfrslot)291   pfr_slot_done( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
292   {
293     PFR_Slot  slot = (PFR_Slot)pfrslot;
294 
295 
296     pfr_glyph_done( &slot->glyph );
297   }
298 
299 
300   FT_LOCAL_DEF( FT_Error )
pfr_slot_load(FT_GlyphSlot pfrslot,FT_Size pfrsize,FT_UInt gindex,FT_Int32 load_flags)301   pfr_slot_load( FT_GlyphSlot  pfrslot,         /* PFR_Slot */
302                  FT_Size       pfrsize,         /* PFR_Size */
303                  FT_UInt       gindex,
304                  FT_Int32      load_flags )
305   {
306     PFR_Slot     slot    = (PFR_Slot)pfrslot;
307     PFR_Size     size    = (PFR_Size)pfrsize;
308     FT_Error     error;
309     PFR_Face     face    = (PFR_Face)pfrslot->face;
310     PFR_Char     gchar;
311     FT_Outline*  outline = &pfrslot->outline;
312     FT_ULong     gps_offset;
313 
314 
315     if ( gindex > 0 )
316       gindex--;
317 
318     if ( !face || gindex >= face->phy_font.num_chars )
319     {
320       error = PFR_Err_Invalid_Argument;
321       goto Exit;
322     }
323 
324     /* try to load an embedded bitmap */
325     if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
326     {
327       error = pfr_slot_load_bitmap( slot, size, gindex );
328       if ( error == 0 )
329         goto Exit;
330     }
331 
332     if ( load_flags & FT_LOAD_SBITS_ONLY )
333     {
334       error = PFR_Err_Invalid_Argument;
335       goto Exit;
336     }
337 
338     gchar               = face->phy_font.chars + gindex;
339     pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
340     outline->n_points   = 0;
341     outline->n_contours = 0;
342     gps_offset          = face->header.gps_section_offset;
343 
344     /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
345     error = pfr_glyph_load( &slot->glyph, face->root.stream,
346                             gps_offset, gchar->gps_offset, gchar->gps_size );
347 
348     if ( !error )
349     {
350       FT_BBox            cbox;
351       FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
352       FT_Pos             advance;
353       FT_Int             em_metrics, em_outline;
354       FT_Bool            scaling;
355 
356 
357       scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
358 
359       /* copy outline data */
360       *outline = slot->glyph.loader->base.outline;
361 
362       outline->flags &= ~FT_OUTLINE_OWNER;
363       outline->flags |= FT_OUTLINE_REVERSE_FILL;
364 
365       if ( size && pfrsize->metrics.y_ppem < 24 )
366         outline->flags |= FT_OUTLINE_HIGH_PRECISION;
367 
368       /* compute the advance vector */
369       metrics->horiAdvance = 0;
370       metrics->vertAdvance = 0;
371 
372       advance    = gchar->advance;
373       em_metrics = face->phy_font.metrics_resolution;
374       em_outline = face->phy_font.outline_resolution;
375 
376       if ( em_metrics != em_outline )
377         advance = FT_MulDiv( advance, em_outline, em_metrics );
378 
379       if ( face->phy_font.flags & PFR_PHY_VERTICAL )
380         metrics->vertAdvance = advance;
381       else
382         metrics->horiAdvance = advance;
383 
384       pfrslot->linearHoriAdvance = metrics->horiAdvance;
385       pfrslot->linearVertAdvance = metrics->vertAdvance;
386 
387       /* make-up vertical metrics(?) */
388       metrics->vertBearingX = 0;
389       metrics->vertBearingY = 0;
390 
391 #if 0 /* some fonts seem to be broken here! */
392 
393       /* Apply the font matrix, if any.                 */
394       /* TODO: Test existing fonts with unusual matrix  */
395       /* whether we have to adjust Units per EM.        */
396       {
397         FT_Matrix font_matrix;
398 
399 
400         font_matrix.xx = face->log_font.matrix[0] << 8;
401         font_matrix.yx = face->log_font.matrix[1] << 8;
402         font_matrix.xy = face->log_font.matrix[2] << 8;
403         font_matrix.yy = face->log_font.matrix[3] << 8;
404 
405         FT_Outline_Transform( outline, &font_matrix );
406       }
407 #endif
408 
409       /* scale when needed */
410       if ( scaling )
411       {
412         FT_Int      n;
413         FT_Fixed    x_scale = pfrsize->metrics.x_scale;
414         FT_Fixed    y_scale = pfrsize->metrics.y_scale;
415         FT_Vector*  vec     = outline->points;
416 
417 
418         /* scale outline points */
419         for ( n = 0; n < outline->n_points; n++, vec++ )
420         {
421           vec->x = FT_MulFix( vec->x, x_scale );
422           vec->y = FT_MulFix( vec->y, y_scale );
423         }
424 
425         /* scale the advance */
426         metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
427         metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
428       }
429 
430       /* compute the rest of the metrics */
431       FT_Outline_Get_CBox( outline, &cbox );
432 
433       metrics->width        = cbox.xMax - cbox.xMin;
434       metrics->height       = cbox.yMax - cbox.yMin;
435       metrics->horiBearingX = cbox.xMin;
436       metrics->horiBearingY = cbox.yMax - metrics->height;
437     }
438 
439   Exit:
440     return error;
441   }
442 
443 
444   /*************************************************************************/
445   /*************************************************************************/
446   /*****                                                               *****/
447   /*****                      KERNING METHOD                           *****/
448   /*****                                                               *****/
449   /*************************************************************************/
450   /*************************************************************************/
451 
452   FT_LOCAL_DEF( FT_Error )
pfr_face_get_kerning(FT_Face pfrface,FT_UInt glyph1,FT_UInt glyph2,FT_Vector * kerning)453   pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
454                         FT_UInt     glyph1,
455                         FT_UInt     glyph2,
456                         FT_Vector*  kerning )
457   {
458     PFR_Face     face     = (PFR_Face)pfrface;
459     FT_Error     error    = PFR_Err_Ok;
460     PFR_PhyFont  phy_font = &face->phy_font;
461     FT_UInt32    code1, code2, pair;
462 
463 
464     kerning->x = 0;
465     kerning->y = 0;
466 
467     if ( glyph1 > 0 )
468       glyph1--;
469 
470     if ( glyph2 > 0 )
471       glyph2--;
472 
473     /* convert glyph indices to character codes */
474     if ( glyph1 > phy_font->num_chars ||
475          glyph2 > phy_font->num_chars )
476       goto Exit;
477 
478     code1 = phy_font->chars[glyph1].char_code;
479     code2 = phy_font->chars[glyph2].char_code;
480     pair  = PFR_KERN_INDEX( code1, code2 );
481 
482     /* now search the list of kerning items */
483     {
484       PFR_KernItem  item   = phy_font->kern_items;
485       FT_Stream     stream = pfrface->stream;
486 
487 
488       for ( ; item; item = item->next )
489       {
490         if ( pair >= item->pair1 && pair <= item->pair2 )
491           goto FoundPair;
492       }
493       goto Exit;
494 
495     FoundPair: /* we found an item, now parse it and find the value if any */
496       if ( FT_STREAM_SEEK( item->offset )                       ||
497            FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
498         goto Exit;
499 
500       {
501         FT_UInt    count       = item->pair_count;
502         FT_UInt    size        = item->pair_size;
503         FT_UInt    power       = (FT_UInt)ft_highpow2( (FT_UInt32)count );
504         FT_UInt    probe       = power * size;
505         FT_UInt    extra       = count - power;
506         FT_Byte*   base        = stream->cursor;
507         FT_Bool    twobytes    = FT_BOOL( item->flags & 1 );
508         FT_Bool    twobyte_adj = FT_BOOL( item->flags & 2 );
509         FT_Byte*   p;
510         FT_UInt32  cpair;
511 
512 
513         if ( extra > 0 )
514         {
515           p = base + extra * size;
516 
517           if ( twobytes )
518             cpair = FT_NEXT_ULONG( p );
519           else
520             cpair = PFR_NEXT_KPAIR( p );
521 
522           if ( cpair == pair )
523             goto Found;
524 
525           if ( cpair < pair )
526           {
527             if ( twobyte_adj )
528               p += 2;
529             else
530               p++;
531             base = p;
532           }
533         }
534 
535         while ( probe > size )
536         {
537           probe >>= 1;
538           p       = base + probe;
539 
540           if ( twobytes )
541             cpair = FT_NEXT_ULONG( p );
542           else
543             cpair = PFR_NEXT_KPAIR( p );
544 
545           if ( cpair == pair )
546             goto Found;
547 
548           if ( cpair < pair )
549             base += probe;
550         }
551 
552         p = base;
553 
554         if ( twobytes )
555           cpair = FT_NEXT_ULONG( p );
556         else
557           cpair = PFR_NEXT_KPAIR( p );
558 
559         if ( cpair == pair )
560         {
561           FT_Int  value;
562 
563 
564         Found:
565           if ( twobyte_adj )
566             value = FT_PEEK_SHORT( p );
567           else
568             value = p[0];
569 
570           kerning->x = item->base_adj + value;
571         }
572       }
573 
574       FT_FRAME_EXIT();
575     }
576 
577   Exit:
578     return error;
579   }
580 
581 /* END */
582