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