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