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